summaryrefslogtreecommitdiff
path: root/cleopatre/devkit/mt7601udrv/common/cmm_wpa.c
diff options
context:
space:
mode:
authorFisher Cheng2013-05-24 16:54:08 +0800
committerJulien Lacour2013-10-01 12:12:48 +0200
commit8c1eb022607c0aba81d93b961abbfb47a2dcc325 (patch)
tree13b1cd55172e93b3d1e5baa7141ba259fd71b0af /cleopatre/devkit/mt7601udrv/common/cmm_wpa.c
parent9e4d9d72dcac9686f1b4720e46e3bb88f6375a1e (diff)
cleo/devkit: add MTK MT7601U drv source code, refs #4011
- Enable Wireless LAN and Wireless extension in linux26.config
Diffstat (limited to 'cleopatre/devkit/mt7601udrv/common/cmm_wpa.c')
-rw-r--r--cleopatre/devkit/mt7601udrv/common/cmm_wpa.c4728
1 files changed, 4728 insertions, 0 deletions
diff --git a/cleopatre/devkit/mt7601udrv/common/cmm_wpa.c b/cleopatre/devkit/mt7601udrv/common/cmm_wpa.c
new file mode 100644
index 0000000000..068ae2c4c5
--- /dev/null
+++ b/cleopatre/devkit/mt7601udrv/common/cmm_wpa.c
@@ -0,0 +1,4728 @@
+/*
+ ***************************************************************************
+ * Ralink Tech Inc.
+ * 4F, No. 2 Technology 5th Rd.
+ * Science-based Industrial Park
+ * Hsin-chu, Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2004, Ralink Technology, Inc.
+ *
+ * All rights reserved. Ralink's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Ralink Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Ralink Technology, Inc. is obtained.
+ ***************************************************************************
+
+ Module Name:
+ wpa.c
+
+ Abstract:
+
+ Revision History:
+ Who When What
+ -------- ---------- ----------------------------------------------
+ Jan Lee 03-07-22 Initial
+ Paul Lin 03-11-28 Modify for supplicant
+*/
+#include "rt_config.h"
+
+/* WPA OUI*/
+UCHAR OUI_WPA[3] = {0x00, 0x50, 0xF2};
+UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00};
+UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01};
+UCHAR OUI_WPA_WEP40[4] = {0x00, 0x50, 0xF2, 0x01};
+UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02};
+UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04};
+UCHAR OUI_WPA_WEP104[4] = {0x00, 0x50, 0xF2, 0x05};
+UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01};
+UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02};
+/* WPA2 OUI*/
+UCHAR OUI_WPA2[3] = {0x00, 0x0F, 0xAC};
+UCHAR OUI_WPA2_WEP40[4] = {0x00, 0x0F, 0xAC, 0x01};
+UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02};
+UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04};
+UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01};
+UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02};
+UCHAR OUI_WPA2_WEP104[4] = {0x00, 0x0F, 0xAC, 0x05};
+UCHAR OUI_WPA2_1X_SHA256[4] = {0x00, 0x0F, 0xAC, 0x05};
+UCHAR OUI_WPA2_PSK_SHA256[4] = {0x00, 0x0F, 0xAC, 0x06};
+
+
+
+static VOID ConstructEapolKeyData(
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN UCHAR GroupKeyWepStatus,
+ IN UCHAR keyDescVer,
+ IN UCHAR MsgType,
+ IN UCHAR DefaultKeyIdx,
+ IN UCHAR *GTK,
+ IN UCHAR *RSNIE,
+ IN UCHAR RSNIE_LEN,
+ OUT PEAPOL_PACKET pMsg);
+
+static VOID WpaEAPPacketAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem);
+
+static VOID WpaEAPOLASFAlertAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem);
+
+static VOID WpaEAPOLLogoffAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem);
+
+static VOID WpaEAPOLStartAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem);
+
+static VOID WpaEAPOLKeyAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem);
+
+/*
+ ==========================================================================
+ Description:
+ association state machine init, including state transition and timer init
+ Parameters:
+ S - pointer to the association state machine
+ ==========================================================================
+ */
+VOID WpaStateMachineInit(
+ IN PRTMP_ADAPTER pAd,
+ IN STATE_MACHINE *S,
+ OUT STATE_MACHINE_FUNC Trans[])
+{
+ StateMachineInit(S, (STATE_MACHINE_FUNC *)Trans, MAX_WPA_PTK_STATE, MAX_WPA_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PTK, WPA_MACHINE_BASE);
+
+ StateMachineSetAction(S, WPA_PTK, MT2_EAPPacket, (STATE_MACHINE_FUNC)WpaEAPPacketAction);
+ StateMachineSetAction(S, WPA_PTK, MT2_EAPOLStart, (STATE_MACHINE_FUNC)WpaEAPOLStartAction);
+ StateMachineSetAction(S, WPA_PTK, MT2_EAPOLLogoff, (STATE_MACHINE_FUNC)WpaEAPOLLogoffAction);
+ StateMachineSetAction(S, WPA_PTK, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction);
+ StateMachineSetAction(S, WPA_PTK, MT2_EAPOLASFAlert, (STATE_MACHINE_FUNC)WpaEAPOLASFAlertAction);
+}
+
+/*
+ ==========================================================================
+ Description:
+ this is state machine function.
+ When receiving EAP packets which is for 802.1x authentication use.
+ Not use in PSK case
+ Return:
+ ==========================================================================
+*/
+VOID WpaEAPPacketAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+}
+
+VOID WpaEAPOLASFAlertAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+}
+
+VOID WpaEAPOLLogoffAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+}
+
+/*
+ ==========================================================================
+ Description:
+ Start 4-way HS when rcv EAPOL_START which may create by our driver in assoc.c
+ Return:
+ ==========================================================================
+*/
+VOID WpaEAPOLStartAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+ MAC_TABLE_ENTRY *pEntry;
+ PHEADER_802_11 pHeader;
+
+
+ DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLStartAction ===> \n"));
+
+ pHeader = (PHEADER_802_11)Elem->Msg;
+
+ /*For normaol PSK, we enqueue an EAPOL-Start command to trigger the process.*/
+ if (Elem->MsgLen == 6)
+ pEntry = MacTableLookup(pAd, Elem->Msg);
+ else
+ {
+ pEntry = MacTableLookup(pAd, pHeader->Addr2);
+#ifdef WSC_AP_SUPPORT
+ /*
+ a WSC enabled AP must ignore EAPOL-Start frames received from clients that associated to
+ the AP with an RSN IE or SSN IE indicating a WPA2-PSK/WPA-PSK authentication method in
+ the assication request. <<from page52 in Wi-Fi Simple Config Specification version 1.0g>>
+ */
+ if (pEntry &&
+ (pEntry->apidx == MAIN_MBSSID) &&
+ (pAd->ApCfg.MBSSID[pEntry->apidx].WscControl.WscConfMode != WSC_DISABLE) &&
+ ((pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) &&
+ pEntry->bWscCapable)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("WPS enabled AP: Ignore EAPOL-Start frames received from clients.\n"));
+ return;
+ }
+#endif /* WSC_AP_SUPPORT */
+ }
+
+ if (pEntry)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, (" PortSecured(%d), WpaState(%d), AuthMode(%d), PMKID_CacheIdx(%d) \n", pEntry->PortSecured, pEntry->WpaState, pEntry->AuthMode, pEntry->PMKID_CacheIdx));
+
+ if ((pEntry->PortSecured == WPA_802_1X_PORT_NOT_SECURED)
+ && (pEntry->WpaState < AS_PTKSTART)
+ && ((pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) || ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) && (pEntry->PMKID_CacheIdx != ENTRY_NOT_FOUND))))
+ {
+ pEntry->PrivacyFilter = Ndis802_11PrivFilter8021xWEP;
+ pEntry->WpaState = AS_INITPSK;
+ pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED;
+ NdisZeroMemory(pEntry->R_Counter, sizeof(pEntry->R_Counter));
+ pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR;
+
+ WPAStart4WayHS(pAd, pEntry, PEER_MSG1_RETRY_EXEC_INTV);
+ }
+ }
+}
+
+/*
+ ==========================================================================
+ Description:
+ This is state machine function.
+ When receiving EAPOL packets which is for 802.1x key management.
+ Use both in WPA, and WPAPSK case.
+ In this function, further dispatch to different functions according to the received packet. 3 categories are :
+ 1. normal 4-way pairwisekey and 2-way groupkey handshake
+ 2. MIC error (Countermeasures attack) report packet from STA.
+ 3. Request for pairwise/group key update from STA
+ Return:
+ ==========================================================================
+*/
+VOID WpaEAPOLKeyAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+ MAC_TABLE_ENTRY *pEntry;
+ PHEADER_802_11 pHeader;
+ PEAPOL_PACKET pEapol_packet;
+ KEY_INFO peerKeyInfo;
+ UINT eapol_len;
+
+
+ DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLKeyAction ===>\n"));
+
+ pHeader = (PHEADER_802_11)Elem->Msg;
+ pEapol_packet = (PEAPOL_PACKET)&Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+ eapol_len = CONV_ARRARY_TO_UINT16(pEapol_packet->Body_Len) + LENGTH_EAPOL_H;
+
+ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
+ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pEapol_packet->KeyDesc.KeyInfo, sizeof(KEY_INFO));
+
+
+ *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo));
+
+ do
+ {
+ pEntry = MacTableLookup(pAd, pHeader->Addr2);
+
+ if (!pEntry || (!IS_ENTRY_CLIENT(pEntry) && !IS_ENTRY_APCLI(pEntry)))
+ break;
+
+ if (pEntry->AuthMode < Ndis802_11AuthModeWPA)
+ break;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPoL-Key frame from STA %02X-%02X-%02X-%02X-%02X-%02X\n", PRINT_MAC(pEntry->Addr)));
+
+ if (eapol_len > Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("The length of EAPoL packet is invalid \n"));
+ break;
+ }
+
+ if (((pEapol_packet->ProVer != EAPOL_VER) && (pEapol_packet->ProVer != EAPOL_VER2)) ||
+ ((pEapol_packet->KeyDesc.Type != WPA1_KEY_DESC) && (pEapol_packet->KeyDesc.Type != WPA2_KEY_DESC)))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n"));
+ break;
+ }
+
+ /* The value 1 shall be used for all EAPOL-Key frames to and from a STA when */
+ /* neither the group nor pairwise ciphers are CCMP for Key Descriptor 1.*/
+ if ((pEntry->WepStatus == Ndis802_11Encryption2Enabled) && (peerKeyInfo.KeyDescVer != KEY_DESC_TKIP))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("Key descripter version not match(TKIP) \n"));
+ break;
+ }
+ /* The value 2 shall be used for all EAPOL-Key frames to and from a STA when */
+ /* either the pairwise or the group cipher is AES-CCMP for Key Descriptor 2 or 3.*/
+ else if ((pEntry->WepStatus == Ndis802_11Encryption3Enabled)
+ && (peerKeyInfo.KeyDescVer != KEY_DESC_AES)
+ && (peerKeyInfo.KeyDescVer != KEY_DESC_EXT))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("Key descripter version not match(AES) pEntry->WepStatus=%d, peerKeyInfo.KeyDescVer=%d\n", pEntry->WepStatus, peerKeyInfo.KeyDescVer));
+ break;
+ }
+
+ /* Check if this STA is in class 3 state and the WPA state is started */
+ if ((pEntry->Sst == SST_ASSOC) && (pEntry->WpaState >= AS_INITPSK))
+ {
+ /* Check the Key Ack (bit 7) of the Key Information to determine the Authenticator */
+ /* or not.*/
+ /* An EAPOL-Key frame that is sent by the Supplicant in response to an EAPOL-*/
+ /* Key frame from the Authenticator must not have the Ack bit set.*/
+ if (peerKeyInfo.KeyAck == 1)
+ {
+ /* The frame is snet by Authenticator. */
+ /* So the Supplicant side shall handle this.*/
+
+ if ((peerKeyInfo.Secure == 0) && (peerKeyInfo.Request == 0) &&
+ (peerKeyInfo.Error == 0) && (peerKeyInfo.KeyType == PAIRWISEKEY))
+ {
+ /*
+ Process
+ 1. the message 1 of 4-way HS in WPA or WPA2
+ EAPOL-Key(0,0,1,0,P,0,0,ANonce,0,DataKD_M1)
+ 2. the message 3 of 4-way HS in WPA
+ EAPOL-Key(0,1,1,1,P,0,KeyRSC,ANonce,MIC,DataKD_M3)
+ */
+ if (peerKeyInfo.KeyMic == 0)
+ PeerPairMsg1Action(pAd, pEntry, Elem);
+ else
+ PeerPairMsg3Action(pAd, pEntry, Elem);
+ }
+ else if ((peerKeyInfo.Secure == 1) &&
+ (peerKeyInfo.KeyMic == 1) &&
+ (peerKeyInfo.Request == 0) &&
+ (peerKeyInfo.Error == 0))
+ {
+ /*
+ Process
+ 1. the message 3 of 4-way HS in WPA2
+ EAPOL-Key(1,1,1,1,P,0,KeyRSC,ANonce,MIC,DataKD_M3)
+ 2. the message 1 of group KS in WPA or WPA2
+ EAPOL-Key(1,1,1,0,G,0,Key RSC,0, MIC,GTK[N])
+ */
+ if (peerKeyInfo.KeyType == PAIRWISEKEY)
+ PeerPairMsg3Action(pAd, pEntry, Elem);
+ else
+ PeerGroupMsg1Action(pAd, pEntry, Elem);
+ }
+ }
+ else
+ {
+ /*
+ The frame is snet by Supplicant.So the Authenticator
+ side shall handle this.
+ */
+#ifdef CONFIG_AP_SUPPORT
+#ifdef QOS_DLS_SUPPORT
+ if ((peerKeyInfo.KeyMic == 1) &&
+ (peerKeyInfo.Secure == 1) &&
+ (peerKeyInfo.Error == 0) &&
+ (peerKeyInfo.KeyType == GROUPKEY) &&
+ (pEapol_packet->KeyDesc.KeyDataLen[1] == 12))
+ {
+ /* This is a ralink proprietary DLS STA-Key processing*/
+ RTMPHandleSTAKey(pAd, pEntry, Elem);
+ }
+ else
+#endif /* QOS_DLS_SUPPORT */
+ if ((peerKeyInfo.KeyMic == 1) &&
+ (peerKeyInfo.Request == 1) &&
+ (peerKeyInfo.Error == 1))
+ {
+ /* The Supplicant uses a single Michael MIC Failure Report frame */
+ /* to report a MIC failure event to the Authenticator. */
+ /* A Michael MIC Failure Report is an EAPOL-Key frame with */
+ /* the following Key Information field bits set to 1: */
+ /* MIC bit, Error bit, Request bit, Secure bit.*/
+
+ DBGPRINT(RT_DEBUG_ERROR, ("Received an Michael MIC Failure Report, active countermeasure \n"));
+ RTMP_HANDLE_COUNTER_MEASURE(pAd, pEntry);
+ }
+ else
+#endif /* CONFIG_AP_SUPPORT */
+ if ((peerKeyInfo.Request == 0) &&
+ (peerKeyInfo.Error == 0) &&
+ (peerKeyInfo.KeyMic == 1))
+ {
+ if (peerKeyInfo.Secure == 0 && peerKeyInfo.KeyType == PAIRWISEKEY)
+ {
+ /* EAPOL-Key(0,1,0,0,P,0,0,SNonce,MIC,Data)*/
+ /* Process 1. message 2 of 4-way HS in WPA or WPA2 */
+ /* 2. message 4 of 4-way HS in WPA */
+ if (CONV_ARRARY_TO_UINT16(pEapol_packet->KeyDesc.KeyDataLen) == 0)
+ {
+ PeerPairMsg4Action(pAd, pEntry, Elem);
+ }
+ else
+ {
+ PeerPairMsg2Action(pAd, pEntry, Elem);
+ }
+ }
+ else if (peerKeyInfo.Secure == 1 && peerKeyInfo.KeyType == PAIRWISEKEY)
+ {
+ /* EAPOL-Key(1,1,0,0,P,0,0,0,MIC,0) */
+ /* Process message 4 of 4-way HS in WPA2*/
+ PeerPairMsg4Action(pAd, pEntry, Elem);
+ }
+ else if (peerKeyInfo.Secure == 1 && peerKeyInfo.KeyType == GROUPKEY)
+ {
+ /* EAPOL-Key(1,1,0,0,G,0,0,0,MIC,0)*/
+ /* Process message 2 of Group key HS in WPA or WPA2 */
+ PeerGroupMsg2Action(pAd, pEntry, &Elem->Msg[LENGTH_802_11], (Elem->MsgLen - LENGTH_802_11));
+ }
+ }
+#ifdef CONFIG_AP_SUPPORT
+ else if ((peerKeyInfo.Request == 1) && (peerKeyInfo.Error == 0))
+ {
+ INT i;
+ UCHAR apidx = pEntry->apidx;
+
+ /* Need to check KeyType for groupkey or pairwise key update, refer to 8021i P.114, */
+ if (peerKeyInfo.KeyType == GROUPKEY)
+ {
+ UINT8 Wcid;
+ PMULTISSID_STRUCT pMbssEntry;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("REQUEST=1, ERROR=0, update group key\n"));
+
+ pMbssEntry = &pAd->ApCfg.MBSSID[apidx];
+
+ GenRandom(pAd, pMbssEntry->Bssid, pMbssEntry->GNonce);
+ pMbssEntry->DefaultKeyId = (pMbssEntry->DefaultKeyId == 1) ? 2 : 1;
+ WpaDeriveGTK(pMbssEntry->GMK,
+ pMbssEntry->GNonce,
+ pMbssEntry->Bssid,
+ pMbssEntry->GTK, LEN_TKIP_GTK);
+
+ for (i = 0; i < MAX_LEN_OF_MAC_TABLE; i++)
+ {
+ if (IS_ENTRY_CLIENT(&pAd->MacTab.Content[i])
+ && (pAd->MacTab.Content[i].WpaState == AS_PTKINITDONE)
+ && (pAd->MacTab.Content[i].apidx == apidx))
+ {
+ pAd->MacTab.Content[i].GTKState = REKEY_NEGOTIATING;
+ WPAStart2WayGroupHS(pAd, &pAd->MacTab.Content[i]);
+ pAd->MacTab.Content[i].ReTryCounter = GROUP_MSG1_RETRY_TIMER_CTR;
+ RTMPModTimer(&pAd->MacTab.Content[i].RetryTimer, PEER_MSG3_RETRY_EXEC_INTV);
+ }
+ }
+
+ /* Get a specific WCID to record this MBSS key attribute */
+ GET_GroupKey_WCID(pAd, Wcid, apidx);
+
+ WPAInstallSharedKey(pAd,
+ pMbssEntry->GroupKeyWepStatus,
+ apidx,
+ pMbssEntry->DefaultKeyId,
+ Wcid,
+ TRUE,
+ pMbssEntry->GTK,
+ LEN_TKIP_GTK);
+
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("REQUEST=1, ERROR= 0, update pairwise key\n"));
+
+ NdisZeroMemory(&pEntry->PairwiseKey, sizeof(CIPHER_KEY));
+
+ /* clear this entry as no-security mode*/
+ AsicRemovePairwiseKeyEntry(pAd, pEntry->Aid);
+
+ pEntry->Sst = SST_ASSOC;
+ if (pEntry->AuthMode == Ndis802_11AuthModeWPA || pEntry->AuthMode == Ndis802_11AuthModeWPA2)
+ pEntry->WpaState = AS_INITPMK;
+ else if (pEntry->AuthMode == Ndis802_11AuthModeWPAPSK || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)
+ pEntry->WpaState = AS_INITPSK;
+
+ pEntry->GTKState = REKEY_NEGOTIATING;
+ pEntry->PrivacyFilter = Ndis802_11PrivFilter8021xWEP;
+ pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR;
+ pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED;
+ NdisZeroMemory(pEntry->R_Counter, sizeof(pEntry->R_Counter));
+
+ WPAStart4WayHS(pAd, pEntry, PEER_MSG1_RETRY_EXEC_INTV);
+ }
+ }
+#endif /* CONFIG_AP_SUPPORT */
+ }
+ }
+ }while(FALSE);
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Copy frame from waiting queue into relative ring buffer and set
+ appropriate ASIC register to kick hardware encryption before really
+ sent out to air.
+
+ Arguments:
+ pAd Pointer to our adapter
+ PNDIS_PACKET Pointer to outgoing Ndis frame
+ NumberOfFrag Number of fragment required
+
+ Return Value:
+ None
+
+ Note:
+
+ ========================================================================
+*/
+VOID RTMPToWirelessSta(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PUCHAR pHeader802_3,
+ IN UINT HdrLen,
+ IN PUCHAR pData,
+ IN UINT DataLen,
+ IN BOOLEAN bClearFrame)
+{
+ PNDIS_PACKET pPacket;
+ NDIS_STATUS Status;
+
+ if ((!pEntry) || (!IS_ENTRY_CLIENT(pEntry) && !IS_ENTRY_APCLI(pEntry)
+ ))
+ return;
+
+ do {
+ /* build a NDIS packet*/
+ Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen);
+ if (Status != NDIS_STATUS_SUCCESS)
+ break;
+
+
+ if (bClearFrame)
+ RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1);
+ else
+ RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0);
+#ifdef CONFIG_AP_SUPPORT
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry))
+ {
+ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS);
+ RTMP_SET_PACKET_MOREDATA(pPacket, FALSE);
+ RTMP_SET_PACKET_NET_DEVICE_APCLI(pPacket, pEntry->MatchAPCLITabIdx);
+ RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid); /* to ApClient links.*/
+ }
+ else
+#endif /* APCLI_SUPPORT */
+#endif /* CONFIG_AP_SUPPORT */
+ {
+ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS);
+
+ RTMP_SET_PACKET_NET_DEVICE_MBSSID(pPacket, MAIN_MBSSID); /* set a default value*/
+ if(pEntry->apidx != 0)
+ RTMP_SET_PACKET_NET_DEVICE_MBSSID(pPacket, pEntry->apidx);
+
+ RTMP_SET_PACKET_WCID(pPacket, (UCHAR)pEntry->Aid);
+ RTMP_SET_PACKET_MOREDATA(pPacket, FALSE);
+ }
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ /* send out the packet */
+ APSendPacket(pAd, pPacket);
+
+ /* Dequeue outgoing frames from TxSwQueue0..3 queue and process it*/
+ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS);
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ } while (FALSE);
+}
+
+/*
+ ==========================================================================
+ Description:
+ Check the validity of the received EAPoL frame
+ Return:
+ TRUE if all parameters are OK,
+ FALSE otherwise
+ ==========================================================================
+ */
+BOOLEAN PeerWpaMessageSanity(
+ IN PRTMP_ADAPTER pAd,
+ IN PEAPOL_PACKET pMsg,
+ IN ULONG MsgLen,
+ IN UCHAR MsgType,
+ IN MAC_TABLE_ENTRY *pEntry)
+{
+ UCHAR mic[LEN_KEY_DESC_MIC], digest[80]; /*, KEYDATA[MAX_LEN_OF_RSNIE];*/
+ UCHAR *KEYDATA = NULL;
+ BOOLEAN bReplayDiff = FALSE;
+ BOOLEAN bWPA2 = FALSE;
+ KEY_INFO EapolKeyInfo;
+ UCHAR GroupKeyIndex = 0;
+
+
+ /* allocate memory */
+ os_alloc_mem(NULL, (UCHAR **)&KEYDATA, MAX_LEN_OF_RSNIE);
+ if (KEYDATA == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: Allocate memory fail!!!\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ NdisZeroMemory(mic, sizeof(mic));
+ NdisZeroMemory(digest, sizeof(digest));
+ NdisZeroMemory(KEYDATA, MAX_LEN_OF_RSNIE);
+ NdisZeroMemory((PUCHAR)&EapolKeyInfo, sizeof(EapolKeyInfo));
+
+ NdisMoveMemory((PUCHAR)&EapolKeyInfo, (PUCHAR)&pMsg->KeyDesc.KeyInfo, sizeof(KEY_INFO));
+
+ *((USHORT *)&EapolKeyInfo) = cpu2le16(*((USHORT *)&EapolKeyInfo));
+
+ /* Choose WPA2 or not*/
+ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
+ bWPA2 = TRUE;
+
+ /* 0. Check MsgType*/
+ if ((MsgType > EAPOL_GROUP_MSG_2) || (MsgType < EAPOL_PAIR_MSG_1))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("The message type is invalid(%d)! \n", MsgType));
+ goto LabelErr;
+ }
+
+ /* 1. Replay counter check */
+ if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1) /* For supplicant*/
+ {
+ /* First validate replay counter, only accept message with larger replay counter.*/
+ /* Let equal pass, some AP start with all zero replay counter*/
+ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY];
+
+ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY);
+ if ((RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY) != 1) &&
+ (RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0))
+ {
+ bReplayDiff = TRUE;
+ }
+ }
+ else if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) /* For authenticator*/
+ {
+ /* check Replay Counter coresponds to MSG from authenticator, otherwise discard*/
+ if (!NdisEqualMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY))
+ {
+ bReplayDiff = TRUE;
+ }
+ }
+
+ /* Replay Counter different condition*/
+ if (bReplayDiff)
+ {
+ /* send wireless event - for replay counter different*/
+ RTMPSendWirelessEvent(pAd, IW_REPLAY_COUNTER_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0);
+
+ if (MsgType < EAPOL_GROUP_MSG_1)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in pairwise msg %d of 4-way handshake!\n", MsgType));
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4)));
+ }
+
+ hex_dump("Receive replay counter ", pMsg->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+ hex_dump("Current replay counter ", pEntry->R_Counter, LEN_KEY_DESC_REPLAY);
+ goto LabelErr;
+ }
+
+ /* 2. Verify MIC except Pairwise Msg1*/
+ if (MsgType != EAPOL_PAIR_MSG_1)
+ {
+ UCHAR rcvd_mic[LEN_KEY_DESC_MIC];
+ UINT eapol_len = CONV_ARRARY_TO_UINT16(pMsg->Body_Len) + 4;
+
+ /* Record the received MIC for check later*/
+ NdisMoveMemory(rcvd_mic, pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+ NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+
+ if (EapolKeyInfo.KeyDescVer == KEY_DESC_TKIP) /* TKIP*/
+ {
+ RT_HMAC_MD5(pEntry->PTK, LEN_PTK_KCK, (PUCHAR)pMsg, eapol_len, mic, MD5_DIGEST_SIZE);
+ }
+ else if (EapolKeyInfo.KeyDescVer == KEY_DESC_AES) /* AES */
+ {
+ RT_HMAC_SHA1(pEntry->PTK, LEN_PTK_KCK, (PUCHAR)pMsg, eapol_len, digest, SHA1_DIGEST_SIZE);
+ NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC);
+ }
+ else if (EapolKeyInfo.KeyDescVer == KEY_DESC_EXT) /* AES-128 */
+ {
+ UINT mlen = AES_KEY128_LENGTH;
+ AES_CMAC((PUCHAR)pMsg, eapol_len, pEntry->PTK, LEN_PTK_KCK, mic, &mlen);
+ }
+
+
+ if (!NdisEqualMemory(rcvd_mic, mic, LEN_KEY_DESC_MIC))
+ {
+ /* send wireless event - for MIC different*/
+ RTMPSendWirelessEvent(pAd, IW_MIC_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0);
+
+ if (MsgType < EAPOL_GROUP_MSG_1)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in pairwise msg %d of 4-way handshake!\n", MsgType));
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4)));
+ }
+
+ hex_dump("Received MIC", rcvd_mic, LEN_KEY_DESC_MIC);
+ hex_dump("Desired MIC", mic, LEN_KEY_DESC_MIC);
+
+ goto LabelErr;
+ }
+ }
+
+ /* 1. Decrypt the Key Data field if GTK is included.*/
+ /* 2. Extract the context of the Key Data field if it exist. */
+ /* The field in pairwise_msg_2_WPA1(WPA2) & pairwise_msg_3_WPA1 is clear.*/
+ /* The field in group_msg_1_WPA1(WPA2) & pairwise_msg_3_WPA2 is encrypted.*/
+ if (CONV_ARRARY_TO_UINT16(pMsg->KeyDesc.KeyDataLen) > 0)
+ {
+ /* Decrypt this field */
+ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1))
+ {
+ if((EapolKeyInfo.KeyDescVer == KEY_DESC_EXT) || (EapolKeyInfo.KeyDescVer == KEY_DESC_AES))
+ {
+ UINT aes_unwrap_len = 0;
+
+ /* AES */
+ AES_Key_Unwrap(pMsg->KeyDesc.KeyData,
+ CONV_ARRARY_TO_UINT16(pMsg->KeyDesc.KeyDataLen),
+ &pEntry->PTK[LEN_PTK_KCK], LEN_PTK_KEK,
+ KEYDATA, &aes_unwrap_len);
+ SET_UINT16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, aes_unwrap_len);
+ }
+ else
+ {
+ TKIP_GTK_KEY_UNWRAP(&pEntry->PTK[LEN_PTK_KCK],
+ pMsg->KeyDesc.KeyIv,
+ pMsg->KeyDesc.KeyData,
+ CONV_ARRARY_TO_UINT16(pMsg->KeyDesc.KeyDataLen),
+ KEYDATA);
+ }
+
+ if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1))
+ GroupKeyIndex = EapolKeyInfo.KeyIndex;
+
+ }
+ else if ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3 && !bWPA2))
+ {
+ NdisMoveMemory(KEYDATA, pMsg->KeyDesc.KeyData, CONV_ARRARY_TO_UINT16(pMsg->KeyDesc.KeyDataLen));
+ }
+ else
+ {
+
+ goto LabelOK;
+ }
+
+ /* Parse Key Data field to */
+ /* 1. verify RSN IE for pairwise_msg_2_WPA1(WPA2) ,pairwise_msg_3_WPA1(WPA2)*/
+ /* 2. verify KDE format for pairwise_msg_3_WPA2, group_msg_1_WPA2*/
+ /* 3. update shared key for pairwise_msg_3_WPA2, group_msg_1_WPA1(WPA2)*/
+ if (!RTMPParseEapolKeyData(pAd, KEYDATA,
+ CONV_ARRARY_TO_UINT16(pMsg->KeyDesc.KeyDataLen),
+ GroupKeyIndex, MsgType, bWPA2, pEntry))
+ {
+ goto LabelErr;
+ }
+ }
+
+LabelOK:
+ if (KEYDATA != NULL)
+ os_free_mem(NULL, KEYDATA);
+ return TRUE;
+
+LabelErr:
+ if (KEYDATA != NULL)
+ os_free_mem(NULL, KEYDATA);
+ return FALSE;
+}
+
+
+/*
+ ==========================================================================
+ Description:
+ This is a function to initilize 4-way handshake
+
+ Return:
+
+ ==========================================================================
+*/
+VOID WPAStart4WayHS(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN ULONG TimeInterval)
+{
+ UCHAR Header802_3[14];
+ UCHAR *mpool;
+ PEAPOL_PACKET pEapolFrame;
+ PUINT8 pBssid = NULL;
+ UCHAR group_cipher = Ndis802_11WEPDisabled;
+#ifdef CONFIG_AP_SUPPORT
+ UCHAR apidx = 0;
+#endif /* CONFIG_AP_SUPPORT */
+
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> WPAStart4WayHS\n"));
+
+ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("[ERROR]WPAStart4WayHS : The interface is closed...\n"));
+ return;
+ }
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ if ((!pEntry) || !IS_ENTRY_CLIENT(pEntry))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("[ERROR]WPAStart4WayHS : The entry doesn't exist.\n"));
+ return;
+ }
+
+ if (pEntry->apidx < pAd->ApCfg.BssidNum)
+ {
+ apidx = pEntry->apidx;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("[ERROR]WPAStart4WayHS : The apidx(%d) is invalid.\n", pEntry->apidx));
+ return;
+ }
+
+ /* pointer to the corresponding position*/
+ pBssid = pAd->ApCfg.MBSSID[apidx].Bssid;
+ group_cipher = pAd->ApCfg.MBSSID[apidx].GroupKeyWepStatus;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ if (pBssid == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("[ERROR]WPAStart4WayHS : No corresponding Authenticator.\n"));
+ return;
+ }
+
+ /* Check the status*/
+ if ((pEntry->WpaState > AS_PTKSTART) || (pEntry->WpaState < AS_INITPMK))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("[ERROR]WPAStart4WayHS : Not expect calling\n"));
+ return;
+ }
+
+#ifdef WSC_AP_SUPPORT
+ if (MAC_ADDR_EQUAL(pEntry->Addr, pAd->ApCfg.MBSSID[apidx].WscControl.EntryAddr) &&
+ pAd->ApCfg.MBSSID[apidx].WscControl.EapMsgRunning)
+ {
+ pEntry->WpaState = AS_NOTUSE;
+ DBGPRINT(RT_DEBUG_ERROR, ("This is a WSC-Enrollee. Not expect calling WPAStart4WayHS here \n"));
+ return;
+ }
+#endif /* WSC_AP_SUPPORT */
+
+ /* Increment replay counter by 1*/
+ ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
+
+ /* Randomly generate ANonce */
+ GenRandom(pAd, (UCHAR *)pBssid, pEntry->ANonce);
+
+ /* Allocate memory for output*/
+ os_alloc_mem(NULL, (PUCHAR *)&mpool, TX_EAPOL_BUFFER);
+ if (mpool == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!%s : no memory!!!\n", __FUNCTION__));
+ return;
+ }
+
+ pEapolFrame = (PEAPOL_PACKET)mpool;
+ NdisZeroMemory(pEapolFrame, TX_EAPOL_BUFFER);
+
+ /* Construct EAPoL message - Pairwise Msg 1*/
+ /* EAPOL-Key(0,0,1,0,P,0,0,ANonce,0,DataKD_M1) */
+ ConstructEapolMsg(pEntry,
+ group_cipher,
+ EAPOL_PAIR_MSG_1,
+ 0, /* Default key index*/
+ pEntry->ANonce,
+ NULL, /* TxRSC*/
+ NULL, /* GTK*/
+ NULL, /* RSNIE*/
+ 0, /* RSNIE length */
+ pEapolFrame);
+
+#ifdef CONFIG_AP_SUPPORT
+ /* If PMKID match in WPA2-enterprise mode, fill PMKID into Key data field and update PMK here */
+ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) && (pEntry->PMKID_CacheIdx != ENTRY_NOT_FOUND))
+ {
+ /* Fill in value for KDE */
+ pEapolFrame->KeyDesc.KeyData[0] = 0xDD;
+ pEapolFrame->KeyDesc.KeyData[2] = 0x00;
+ pEapolFrame->KeyDesc.KeyData[3] = 0x0F;
+ pEapolFrame->KeyDesc.KeyData[4] = 0xAC;
+ pEapolFrame->KeyDesc.KeyData[5] = 0x04;
+
+ NdisMoveMemory(&pEapolFrame->KeyDesc.KeyData[6], &pAd->ApCfg.MBSSID[apidx].PMKIDCache.BSSIDInfo[pEntry->PMKID_CacheIdx].PMKID, LEN_PMKID);
+ NdisMoveMemory(&pAd->ApCfg.MBSSID[apidx].PMK, &pAd->ApCfg.MBSSID[apidx].PMKIDCache.BSSIDInfo[pEntry->PMKID_CacheIdx].PMK, PMK_LEN);
+
+ pEapolFrame->KeyDesc.KeyData[1] = 0x14;/* 4+LEN_PMKID*/
+ INC_UINT16_TO_ARRARY(pEapolFrame->KeyDesc.KeyDataLen, 6 + LEN_PMKID);
+ INC_UINT16_TO_ARRARY(pEapolFrame->Body_Len, 6 + LEN_PMKID);
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ /* Make outgoing frame*/
+ MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
+ RTMPToWirelessSta(pAd, pEntry, Header802_3,
+ LENGTH_802_3, (PUCHAR)pEapolFrame,
+ CONV_ARRARY_TO_UINT16(pEapolFrame->Body_Len) + 4,
+ (pEntry->PortSecured == WPA_802_1X_PORT_SECURED) ? FALSE : TRUE);
+
+ /* Trigger Retry Timer*/
+ RTMPModTimer(&pEntry->RetryTimer, TimeInterval);
+
+ /* Update State*/
+ pEntry->WpaState = AS_PTKSTART;
+
+ os_free_mem(NULL, mpool);
+
+ DBGPRINT(RT_DEBUG_TRACE, ("<=== WPAStart4WayHS: send Msg1 of 4-way \n"));
+
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Process Pairwise key Msg-1 of 4-way handshaking and send Msg-2
+
+ Arguments:
+ pAd Pointer to our adapter
+ Elem Message body
+
+ Return Value:
+ None
+
+ Note:
+
+ ========================================================================
+*/
+VOID PeerPairMsg1Action(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+ UCHAR PTK[80];
+ UCHAR Header802_3[14];
+ PEAPOL_PACKET pMsg1;
+ UINT MsgLen;
+ UCHAR *mpool;
+ PEAPOL_PACKET pEapolFrame;
+ PUINT8 pCurrentAddr = NULL;
+ PUINT8 pmk_ptr = NULL;
+ UCHAR group_cipher = Ndis802_11WEPDisabled;
+ PUINT8 rsnie_ptr = NULL;
+ UCHAR rsnie_len = 0;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg1Action \n"));
+
+ if ((!pEntry) || (!IS_ENTRY_CLIENT(pEntry) && !IS_ENTRY_APCLI(pEntry)))
+ return;
+
+ if (Elem->MsgLen < (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H + MIN_LEN_OF_EAPOL_KEY_MSG))
+ return;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry))
+ {
+ UINT IfIndex = 0;
+
+ IfIndex = pEntry->MatchAPCLITabIdx;
+ if (IfIndex >= MAX_APCLI_NUM)
+ return;
+
+ pCurrentAddr = pAd->ApCfg.ApCliTab[IfIndex].CurrentAddress;
+ pmk_ptr = pAd->ApCfg.ApCliTab[IfIndex].PMK;
+ group_cipher = pAd->ApCfg.ApCliTab[IfIndex].GroupCipher;
+ rsnie_ptr = pAd->ApCfg.ApCliTab[IfIndex].RSN_IE;
+ rsnie_len = pAd->ApCfg.ApCliTab[IfIndex].RSNIE_Len;
+ }
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ if (pCurrentAddr == NULL)
+ return;
+
+ /* Store the received frame*/
+ pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+ MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
+
+ /* Sanity Check peer Pairwise message 1 - Replay Counter*/
+ if (PeerWpaMessageSanity(pAd, pMsg1, MsgLen, EAPOL_PAIR_MSG_1, pEntry) == FALSE)
+ return;
+
+ /* Store Replay counter, it will use to verify message 3 and construct message 2*/
+ NdisMoveMemory(pEntry->R_Counter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+ /* Store ANonce*/
+ NdisMoveMemory(pEntry->ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE);
+
+ /* Generate random SNonce*/
+ GenRandom(pAd, (UCHAR *)pCurrentAddr, pEntry->SNonce);
+
+ {
+ /* Calculate PTK(ANonce, SNonce)*/
+ WpaDerivePTK(pAd,
+ pmk_ptr,
+ pEntry->ANonce,
+ pEntry->Addr,
+ pEntry->SNonce,
+ pCurrentAddr,
+ PTK,
+ LEN_PTK);
+
+ /* Save key to PTK entry*/
+ NdisMoveMemory(pEntry->PTK, PTK, LEN_PTK);
+ }
+
+ /* Update WpaState*/
+ pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
+
+ /* Allocate memory for output*/
+ os_alloc_mem(NULL, (PUCHAR *)&mpool, TX_EAPOL_BUFFER);
+ if (mpool == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!%s : no memory!!!\n", __FUNCTION__));
+ return;
+ }
+
+ pEapolFrame = (PEAPOL_PACKET)mpool;
+ NdisZeroMemory(pEapolFrame, TX_EAPOL_BUFFER);
+
+ /* Construct EAPoL message - Pairwise Msg 2*/
+ /* EAPOL-Key(0,1,0,0,P,0,0,SNonce,MIC,DataKD_M2)*/
+ ConstructEapolMsg(pEntry,
+ group_cipher,
+ EAPOL_PAIR_MSG_2,
+ 0, /* DefaultKeyIdx*/
+ pEntry->SNonce,
+ NULL, /* TxRsc*/
+ NULL, /* GTK*/
+ (UCHAR *)rsnie_ptr,
+ rsnie_len,
+ pEapolFrame);
+
+ /* Make outgoing frame*/
+ MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
+
+ RTMPToWirelessSta(pAd, pEntry,
+ Header802_3, sizeof(Header802_3), (PUCHAR)pEapolFrame,
+ CONV_ARRARY_TO_UINT16(pEapolFrame->Body_Len) + 4, TRUE);
+
+ os_free_mem(NULL, mpool);
+
+ DBGPRINT(RT_DEBUG_TRACE, ("<=== PeerPairMsg1Action: send Msg2 of 4-way \n"));
+}
+
+
+/*
+ ==========================================================================
+ Description:
+ When receiving the second packet of 4-way pairwisekey handshake.
+ Return:
+ ==========================================================================
+*/
+VOID PeerPairMsg2Action(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+ UCHAR PTK[80];
+ BOOLEAN Cancelled;
+ PHEADER_802_11 pHeader;
+ UCHAR *mpool;
+ PEAPOL_PACKET pEapolFrame;
+ PEAPOL_PACKET pMsg2;
+ UINT MsgLen;
+ UCHAR Header802_3[LENGTH_802_3];
+ UCHAR TxTsc[6];
+ PUINT8 pBssid = NULL;
+ PUINT8 pmk_ptr = NULL;
+ PUINT8 gtk_ptr = NULL;
+ UCHAR default_key = 0;
+ UCHAR group_cipher = Ndis802_11WEPDisabled;
+ PUINT8 rsnie_ptr = NULL;
+ UCHAR rsnie_len = 0;
+#ifdef CONFIG_AP_SUPPORT
+ UCHAR apidx = 0;
+#endif /* CONFIG_AP_SUPPORT */
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg2Action \n"));
+
+ if ((!pEntry) || !IS_ENTRY_CLIENT(pEntry))
+ return;
+
+ if (Elem->MsgLen < (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H + MIN_LEN_OF_EAPOL_KEY_MSG))
+ return;
+
+ /* check Entry in valid State*/
+ if (pEntry->WpaState < AS_PTKSTART)
+ return;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ if (pEntry->apidx >= pAd->ApCfg.BssidNum)
+ return;
+ else
+ apidx = pEntry->apidx;
+
+ pBssid = pAd->ApCfg.MBSSID[apidx].Bssid;
+ pmk_ptr = pAd->ApCfg.MBSSID[apidx].PMK;
+ gtk_ptr = pAd->ApCfg.MBSSID[apidx].GTK;
+ group_cipher = pAd->ApCfg.MBSSID[apidx].GroupKeyWepStatus;
+ default_key = pAd->ApCfg.MBSSID[apidx].DefaultKeyId;
+
+ /* Get Group TxTsc form Asic*/
+ RTMPGetTxTscFromAsic(pAd, apidx, TxTsc);
+
+ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA) || (pEntry->AuthMode == Ndis802_11AuthModeWPAPSK))
+ {
+ rsnie_len = pAd->ApCfg.MBSSID[apidx].RSNIE_Len[0];
+ rsnie_ptr = &pAd->ApCfg.MBSSID[apidx].RSN_IE[0][0];
+ }
+ else
+ {
+ if ((pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK) ||
+ (pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPA1WPA2))
+ {
+ rsnie_len = pAd->ApCfg.MBSSID[apidx].RSNIE_Len[1];
+ rsnie_ptr = &pAd->ApCfg.MBSSID[apidx].RSN_IE[1][0];
+ }
+ else
+ {
+ rsnie_len = pAd->ApCfg.MBSSID[apidx].RSNIE_Len[0];
+ rsnie_ptr = &pAd->ApCfg.MBSSID[apidx].RSN_IE[0][0];
+ }
+ }
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+
+ /* pointer to 802.11 header*/
+ pHeader = (PHEADER_802_11)Elem->Msg;
+
+ /* skip 802.11_header(24-byte) and LLC_header(8) */
+ pMsg2 = (PEAPOL_PACKET)&Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+ MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
+
+ /* Store SNonce*/
+ NdisMoveMemory(pEntry->SNonce, pMsg2->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE);
+
+ {
+ /* Derive PTK*/
+ if ((pmk_ptr == NULL) || (pBssid == NULL))
+ {
+ DBGPRINT(RT_DEBUG_ERROR,
+ ("%s: pmk_ptr or pBssid == NULL!\n", __FUNCTION__));
+ return;
+ }
+
+ WpaDerivePTK(pAd,
+ (UCHAR *)pmk_ptr,
+ pEntry->ANonce, /* ANONCE*/
+ (UCHAR *)pBssid,
+ pEntry->SNonce, /* SNONCE*/
+ pEntry->Addr,
+ PTK,
+ LEN_PTK);
+
+ NdisMoveMemory(pEntry->PTK, PTK, LEN_PTK);
+ }
+
+ /* Sanity Check peer Pairwise message 2 - Replay Counter, MIC, RSNIE*/
+ if (PeerWpaMessageSanity(pAd, pMsg2, MsgLen, EAPOL_PAIR_MSG_2, pEntry) == FALSE)
+ return;
+
+ do
+ {
+ /* Allocate memory for input*/
+ os_alloc_mem(NULL, (PUCHAR *)&mpool, TX_EAPOL_BUFFER);
+ if (mpool == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!%s : no memory!!!\n", __FUNCTION__));
+ return;
+ }
+
+ pEapolFrame = (PEAPOL_PACKET)mpool;
+ NdisZeroMemory(pEapolFrame, TX_EAPOL_BUFFER);
+
+ /* delete retry timer*/
+ RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
+
+ /* Change state*/
+ pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
+
+ /* Increment replay counter by 1*/
+ ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
+
+ /* Construct EAPoL message - Pairwise Msg 3*/
+ ConstructEapolMsg(pEntry,
+ group_cipher,
+ EAPOL_PAIR_MSG_3,
+ default_key,
+ pEntry->ANonce,
+ TxTsc,
+ (UCHAR *)gtk_ptr,
+ (UCHAR *)rsnie_ptr,
+ rsnie_len,
+ pEapolFrame);
+
+ /* Make outgoing frame*/
+ MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
+ RTMPToWirelessSta(pAd, pEntry, Header802_3, LENGTH_802_3,
+ (PUCHAR)pEapolFrame,
+ CONV_ARRARY_TO_UINT16(pEapolFrame->Body_Len) + 4,
+ (pEntry->PortSecured == WPA_802_1X_PORT_SECURED) ? FALSE : TRUE);
+
+ pEntry->ReTryCounter = PEER_MSG3_RETRY_TIMER_CTR;
+ RTMPSetTimer(&pEntry->RetryTimer, PEER_MSG3_RETRY_EXEC_INTV);
+
+ /* Update State*/
+ pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
+
+ os_free_mem(NULL, mpool);
+
+ }while(FALSE);
+
+ DBGPRINT(RT_DEBUG_TRACE, ("<=== PeerPairMsg2Action: send Msg3 of 4-way \n"));
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Process Pairwise key Msg 3 of 4-way handshaking and send Msg 4
+
+ Arguments:
+ pAd Pointer to our adapter
+ Elem Message body
+
+ Return Value:
+ None
+
+ Note:
+
+ ========================================================================
+*/
+VOID PeerPairMsg3Action(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+ PHEADER_802_11 pHeader;
+ UCHAR Header802_3[14];
+ UCHAR *mpool;
+ PEAPOL_PACKET pEapolFrame;
+ PEAPOL_PACKET pMsg3;
+ UINT MsgLen;
+ PUINT8 pCurrentAddr = NULL;
+ UCHAR group_cipher = Ndis802_11WEPDisabled;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg3Action \n"));
+
+ if ((!pEntry) || (!IS_ENTRY_CLIENT(pEntry) && !IS_ENTRY_APCLI(pEntry)))
+ return;
+
+ if (Elem->MsgLen < (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H + MIN_LEN_OF_EAPOL_KEY_MSG))
+ return;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry))
+ {
+ UINT IfIndex = 0;
+
+ IfIndex = pEntry->MatchAPCLITabIdx;
+ if (IfIndex >= MAX_APCLI_NUM)
+ return;
+
+ pCurrentAddr = pAd->ApCfg.ApCliTab[IfIndex].CurrentAddress;
+ group_cipher = pAd->ApCfg.ApCliTab[IfIndex].GroupCipher;
+
+ }
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ if (pCurrentAddr == NULL)
+ return;
+
+ /* Record 802.11 header & the received EAPOL packet Msg3*/
+ pHeader = (PHEADER_802_11) Elem->Msg;
+ pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+ MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
+
+ /* Sanity Check peer Pairwise message 3 - Replay Counter, MIC, RSNIE*/
+ if (PeerWpaMessageSanity(pAd, pMsg3, MsgLen, EAPOL_PAIR_MSG_3, pEntry) == FALSE)
+ return;
+
+ /* Save Replay counter, it will use construct message 4*/
+ NdisMoveMemory(pEntry->R_Counter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+ /* Double check ANonce*/
+ if (!NdisEqualMemory(pEntry->ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE))
+ {
+ return;
+ }
+
+ /* Allocate memory for output*/
+ os_alloc_mem(NULL, (PUCHAR *)&mpool, TX_EAPOL_BUFFER);
+ if (mpool == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!%s : no memory!!!\n", __FUNCTION__));
+ return;
+ }
+
+ pEapolFrame = (PEAPOL_PACKET)mpool;
+ NdisZeroMemory(pEapolFrame, TX_EAPOL_BUFFER);
+
+ /* Construct EAPoL message - Pairwise Msg 4*/
+ ConstructEapolMsg(pEntry,
+ group_cipher,
+ EAPOL_PAIR_MSG_4,
+ 0, /* group key index not used in message 4*/
+ NULL, /* Nonce not used in message 4*/
+ NULL, /* TxRSC not used in message 4*/
+ NULL, /* GTK not used in message 4*/
+ NULL, /* RSN IE not used in message 4*/
+ 0,
+ pEapolFrame);
+
+ /* Update WpaState*/
+ pEntry->WpaState = AS_PTKINITDONE;
+ /* Update pairwise key */
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry))
+ APCliInstallPairwiseKey(pAd, pEntry);
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ /* open 802.1x port control and privacy filter*/
+ if (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK ||
+ pEntry->AuthMode == Ndis802_11AuthModeWPA2)
+ {
+ pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
+ pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
+#ifdef CONFIG_MULTI_CHANNEL
+ if (pAd->Multi_Channel_Enable == TRUE)
+ {
+ MultiChannelTimerStart(pAd,pEntry);
+ }
+#endif /*CONFIG_MULTI_CHANNEL*/
+
+
+ DBGPRINT(RT_DEBUG_TRACE, ("PeerPairMsg3Action: AuthMode(%s) PairwiseCipher(%s) GroupCipher(%s) \n",
+ GetAuthMode(pEntry->AuthMode),
+ GetEncryptType(pEntry->WepStatus),
+ GetEncryptType(group_cipher)));
+ }
+ else
+ {
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef APCLI_SUPPORT
+ /* Patch issue with gateway AP*/
+ /* In WPA mode, AP doesn't send out message 1 of group-key HS.*/
+ /* So, Supplicant shall maintain a timeout action to disconnect */
+ /* this link.*/
+ /* Todo - Does it need to apply to STA ?*/
+ if (IS_ENTRY_APCLI(pEntry))
+ RTMPSetTimer(&pEntry->RetryTimer, PEER_GROUP_KEY_UPDATE_INIV);
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+ }
+
+ /* Init 802.3 header and send out*/
+ MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
+ RTMPToWirelessSta(pAd, pEntry,
+ Header802_3, sizeof(Header802_3),
+ (PUCHAR)pEapolFrame,
+ CONV_ARRARY_TO_UINT16(pEapolFrame->Body_Len) + 4, TRUE);
+
+ os_free_mem(NULL, mpool);
+
+
+ DBGPRINT(RT_DEBUG_TRACE, ("<=== PeerPairMsg3Action: send Msg4 of 4-way \n"));
+}
+
+/*
+ ==========================================================================
+ Description:
+ When receiving the last packet of 4-way pairwisekey handshake.
+ Initilize 2-way groupkey handshake following.
+ Return:
+ ==========================================================================
+*/
+VOID PeerPairMsg4Action(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+ PEAPOL_PACKET pMsg4;
+ PHEADER_802_11 pHeader;
+ UINT MsgLen;
+ BOOLEAN Cancelled;
+ UCHAR group_cipher = Ndis802_11WEPDisabled;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg4Action\n"));
+
+ do
+ {
+ if ((!pEntry) || !IS_ENTRY_CLIENT(pEntry))
+ break;
+
+ if (Elem->MsgLen < (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H + MIN_LEN_OF_EAPOL_KEY_MSG ) )
+ break;
+
+ if (pEntry->WpaState < AS_PTKINIT_NEGOTIATING)
+ break;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ UCHAR apidx = 0;
+
+ if (pEntry->apidx >= pAd->ApCfg.BssidNum)
+ break;
+ else
+ apidx = pEntry->apidx;
+
+ group_cipher = pAd->ApCfg.MBSSID[apidx].GroupKeyWepStatus;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ /* pointer to 802.11 header*/
+ pHeader = (PHEADER_802_11)Elem->Msg;
+
+ /* skip 802.11_header(24-byte) and LLC_header(8) */
+ pMsg4 = (PEAPOL_PACKET)&Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+ MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
+
+ /* Sanity Check peer Pairwise message 4 - Replay Counter, MIC*/
+ if (PeerWpaMessageSanity(pAd, pMsg4, MsgLen, EAPOL_PAIR_MSG_4, pEntry) == FALSE)
+ break;
+
+ /* 3. Install pairwise key */
+ WPAInstallPairwiseKey(pAd, pEntry->apidx, pEntry, TRUE);
+
+ /* 4. upgrade state */
+ pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
+ pEntry->WpaState = AS_PTKINITDONE;
+ pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
+
+#ifdef WSC_AP_SUPPORT
+ if (pAd->ApCfg.MBSSID[pEntry->apidx].WscControl.WscConfMode != WSC_DISABLE)
+ WscInformFromWPA(pEntry);
+#endif /* WSC_AP_SUPPORT */
+
+ if (pEntry->AuthMode == Ndis802_11AuthModeWPA2 ||
+ pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)
+ {
+ pEntry->GTKState = REKEY_ESTABLISHED;
+ RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
+
+#ifdef CONFIG_AP_SUPPORT
+#ifdef DOT1X_SUPPORT
+ if (pEntry->AuthMode == Ndis802_11AuthModeWPA2)
+ {
+ UCHAR PMK_key[20];
+ UCHAR digest[80];
+
+ /* Calculate PMKID, refer to IEEE 802.11i-2004 8.5.1.2*/
+ NdisMoveMemory(&PMK_key[0], "PMK Name", 8);
+ NdisMoveMemory(&PMK_key[8], pAd->ApCfg.MBSSID[pEntry->apidx].Bssid, MAC_ADDR_LEN);
+ NdisMoveMemory(&PMK_key[14], pEntry->Addr, MAC_ADDR_LEN);
+ RT_HMAC_SHA1(pAd->ApCfg.MBSSID[pEntry->apidx].PMK, PMK_LEN, PMK_key, 20, digest, SHA1_DIGEST_SIZE);
+ RTMPAddPMKIDCache(pAd, pEntry->apidx, pEntry->Addr, digest, pAd->ApCfg.MBSSID[pEntry->apidx].PMK);
+ DBGPRINT(RT_DEBUG_TRACE, ("Calc PMKID=%02x:%02x:%02x:%02x:%02x:%02x\n", digest[0],digest[1],digest[2],digest[3],digest[4],digest[5]));
+ }
+#endif /* DOT1X_SUPPORT */
+#endif /* CONFIG_AP_SUPPORT */
+
+ /* send wireless event - for set key done WPA2*/
+ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0);
+
+ DBGPRINT(RT_DEBUG_OFF, ("AP SETKEYS DONE - WPA2, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
+ pEntry->AuthMode, GetAuthMode(pEntry->AuthMode),
+ pEntry->WepStatus, GetEncryptType(pEntry->WepStatus),
+ group_cipher,
+ GetEncryptType(group_cipher)));
+ }
+ else
+ {
+ /* 5. init Group 2-way handshake if necessary.*/
+ WPAStart2WayGroupHS(pAd, pEntry);
+
+ pEntry->ReTryCounter = GROUP_MSG1_RETRY_TIMER_CTR;
+ RTMPModTimer(&pEntry->RetryTimer, PEER_MSG3_RETRY_EXEC_INTV);
+ }
+ }while(FALSE);
+
+}
+
+/*
+ ==========================================================================
+ Description:
+ This is a function to send the first packet of 2-way groupkey handshake
+ Return:
+
+ ==========================================================================
+*/
+VOID WPAStart2WayGroupHS(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry)
+{
+ UCHAR Header802_3[14];
+ UCHAR TxTsc[6];
+ UCHAR *mpool;
+ PEAPOL_PACKET pEapolFrame;
+ UCHAR group_cipher = Ndis802_11WEPDisabled;
+ UCHAR default_key = 0;
+ PUINT8 gnonce_ptr = NULL;
+ PUINT8 gtk_ptr = NULL;
+ PUINT8 pBssid = NULL;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> WPAStart2WayGroupHS\n"));
+
+ if ((!pEntry) || !IS_ENTRY_CLIENT(pEntry))
+ return;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ UCHAR apidx = 0;
+
+ if (pEntry->apidx >= pAd->ApCfg.BssidNum)
+ return;
+ else
+ apidx = pEntry->apidx;
+
+ group_cipher = pAd->ApCfg.MBSSID[apidx].GroupKeyWepStatus;
+ default_key = pAd->ApCfg.MBSSID[apidx].DefaultKeyId;
+ gnonce_ptr = pAd->ApCfg.MBSSID[apidx].GNonce;
+ gtk_ptr = pAd->ApCfg.MBSSID[apidx].GTK;
+ pBssid = pAd->ApCfg.MBSSID[apidx].Bssid;
+
+ /* Get Group TxTsc form Asic*/
+ RTMPGetTxTscFromAsic(pAd, apidx, TxTsc);
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ /* Allocate memory for output*/
+ os_alloc_mem(NULL, (PUCHAR *)&mpool, TX_EAPOL_BUFFER);
+ if (mpool == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!%s : no memory!!!\n", __FUNCTION__));
+ return;
+ }
+
+ pEapolFrame = (PEAPOL_PACKET)mpool;
+ NdisZeroMemory(pEapolFrame, TX_EAPOL_BUFFER);
+
+ /* Increment replay counter by 1*/
+ ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
+
+ /* Construct EAPoL message - Group Msg 1*/
+ ConstructEapolMsg(pEntry,
+ group_cipher,
+ EAPOL_GROUP_MSG_1,
+ default_key,
+ (UCHAR *)gnonce_ptr,
+ TxTsc,
+ (UCHAR *)gtk_ptr,
+ NULL,
+ 0,
+ pEapolFrame);
+
+ /* Make outgoing frame*/
+ if (pBssid == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pBssid == NULL!\n", __FUNCTION__));
+ return;
+ }
+
+ MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
+ RTMPToWirelessSta(pAd, pEntry,
+ Header802_3, LENGTH_802_3,
+ (PUCHAR)pEapolFrame,
+ CONV_ARRARY_TO_UINT16(pEapolFrame->Body_Len) + 4, FALSE);
+
+ os_free_mem(NULL, mpool);
+
+ DBGPRINT(RT_DEBUG_TRACE, ("<=== WPAStart2WayGroupHS : send out Group Message 1 \n"));
+
+ return;
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Process Group key 2-way handshaking
+
+ Arguments:
+ pAd Pointer to our adapter
+ Elem Message body
+
+ Return Value:
+ None
+
+ Note:
+
+ ========================================================================
+*/
+VOID PeerGroupMsg1Action(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN MLME_QUEUE_ELEM *Elem)
+{
+ UCHAR Header802_3[14];
+ UCHAR *mpool;
+ PEAPOL_PACKET pEapolFrame;
+ PEAPOL_PACKET pGroup;
+ UINT MsgLen;
+ UCHAR default_key = 0;
+ UCHAR group_cipher = Ndis802_11WEPDisabled;
+ PUINT8 pCurrentAddr = NULL;
+#ifdef APCLI_SUPPORT
+ BOOLEAN Cancelled;
+#endif /* APCLI_SUPPORT */
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> PeerGroupMsg1Action \n"));
+
+ if ((!pEntry) || (!IS_ENTRY_CLIENT(pEntry) && !IS_ENTRY_APCLI(pEntry)))
+ return;
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry))
+ {
+ UINT IfIndex = 0;
+
+ IfIndex = pEntry->MatchAPCLITabIdx;
+ if (IfIndex >= MAX_APCLI_NUM)
+ return;
+
+ pCurrentAddr = pAd->ApCfg.ApCliTab[IfIndex].CurrentAddress;
+ group_cipher = pAd->ApCfg.ApCliTab[IfIndex].GroupCipher;
+ default_key = pAd->ApCfg.ApCliTab[IfIndex].DefaultKeyId;
+
+ }
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ if (pCurrentAddr == NULL)
+ return;
+
+ /* Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8)*/
+ pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+ MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
+
+ /* Sanity Check peer group message 1 - Replay Counter, MIC, RSNIE*/
+ if (PeerWpaMessageSanity(pAd, pGroup, MsgLen, EAPOL_GROUP_MSG_1, pEntry) == FALSE)
+ return;
+
+ /* delete retry timer*/
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef APCLI_SUPPORT
+ /* Patch issue with gateway AP*/
+ /* In WPA mode, AP doesn't send out message 1 of group-key HS.*/
+ /* So, Supplicant shall maintain a timeout action to disconnect */
+ /* this link.*/
+ /* Todo - Does it need to apply to STA ?*/
+ if (IS_ENTRY_APCLI(pEntry))
+ RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
+#endif /* APCLI_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ /* Save Replay counter, it will use to construct message 2*/
+ NdisMoveMemory(pEntry->R_Counter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+ /* Allocate memory for output*/
+ os_alloc_mem(NULL, (PUCHAR *)&mpool, TX_EAPOL_BUFFER);
+ if (mpool == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!%s : no memory!!!\n", __FUNCTION__));
+ return;
+ }
+
+ pEapolFrame = (PEAPOL_PACKET)mpool;
+ NdisZeroMemory(pEapolFrame, TX_EAPOL_BUFFER);
+
+
+ /* Construct EAPoL message - Group Msg 2*/
+ ConstructEapolMsg(pEntry,
+ group_cipher,
+ EAPOL_GROUP_MSG_2,
+ default_key,
+ NULL, /* Nonce not used*/
+ NULL, /* TxRSC not used*/
+ NULL, /* GTK not used*/
+ NULL, /* RSN IE not used*/
+ 0,
+ pEapolFrame);
+
+ /* open 802.1x port control and privacy filter*/
+ pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
+ pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
+
+
+ DBGPRINT(RT_DEBUG_TRACE, ("PeerGroupMsg1Action: AuthMode(%s) PairwiseCipher(%s) GroupCipher(%s) \n",
+ GetAuthMode(pEntry->AuthMode),
+ GetEncryptType(pEntry->WepStatus),
+ GetEncryptType(group_cipher)));
+
+ /* init header and Fill Packet and send Msg 2 to authenticator */
+ MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
+
+
+ RTMPToWirelessSta(pAd, pEntry,
+ Header802_3, sizeof(Header802_3),
+ (PUCHAR)pEapolFrame,
+ CONV_ARRARY_TO_UINT16(pEapolFrame->Body_Len) + 4, FALSE);
+
+ os_free_mem(NULL, mpool);
+
+
+ DBGPRINT(RT_DEBUG_TRACE, ("<=== PeerGroupMsg1Action: send group message 2\n"));
+}
+
+
+VOID EnqueueStartForPSKExec(
+ IN PVOID SystemSpecific1,
+ IN PVOID FunctionContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3)
+{
+ MAC_TABLE_ENTRY *pEntry = (PMAC_TABLE_ENTRY) FunctionContext;
+
+ if ((pEntry) && IS_ENTRY_CLIENT(pEntry) && (pEntry->WpaState < AS_PTKSTART))
+ {
+ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)pEntry->pAd;
+
+ switch (pEntry->EnqueueEapolStartTimerRunning)
+ {
+ case EAPOL_START_PSK:
+ DBGPRINT(RT_DEBUG_TRACE, ("Enqueue EAPoL-Start-PSK for sta(%02x:%02x:%02x:%02x:%02x:%02x) \n", PRINT_MAC(pEntry->Addr)));
+
+ MlmeEnqueue(pAd, WPA_STATE_MACHINE, MT2_EAPOLStart, 6, &pEntry->Addr, 0);
+ break;
+#ifdef CONFIG_AP_SUPPORT
+#ifdef DOT1X_SUPPORT
+ case EAPOL_START_1X:
+ DBGPRINT(RT_DEBUG_TRACE, ("Enqueue EAPoL-Start-1X for sta(%02x:%02x:%02x:%02x:%02x:%02x) \n", PRINT_MAC(pEntry->Addr)));
+
+ DOT1X_EapTriggerAction(pAd, pEntry);
+ break;
+#endif /* DOT1X_SUPPORT */
+#endif /* CONFIG_AP_SUPPORT */
+ default:
+ break;
+
+ }
+ }
+ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE;
+
+}
+
+
+VOID MlmeDeAuthAction(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN USHORT Reason,
+ IN BOOLEAN bDataFrameFirst)
+{
+ PUCHAR pOutBuffer = NULL;
+ ULONG FrameLen = 0;
+ HEADER_802_11 DeAuthHdr;
+ NDIS_STATUS NStatus;
+
+ if (pEntry)
+ {
+ /* Send out a Deauthentication request frame*/
+ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
+ if (NStatus != NDIS_STATUS_SUCCESS)
+ return;
+
+ /* send wireless event - for send disassication */
+ RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0);
+
+ DBGPRINT(RT_DEBUG_TRACE, ("Send DEAUTH frame with ReasonCode(%d) to %02x:%02x:%02x:%02x:%02x:%02x \n",Reason, PRINT_MAC(pEntry->Addr)));
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ MgtMacHeaderInit(pAd, &DeAuthHdr, SUBTYPE_DEAUTH, 0, pEntry->Addr, pAd->ApCfg.MBSSID[pEntry->apidx].Bssid);
+ }
+#endif /* CONFIG_AP_SUPPORT */
+ MakeOutgoingFrame(pOutBuffer, &FrameLen,
+ sizeof(HEADER_802_11), &DeAuthHdr,
+ 2, &Reason,
+ END_OF_ARGS);
+
+
+
+ if (bDataFrameFirst)
+ MiniportMMRequest(pAd, MGMT_USE_QUEUE_FLAG, pOutBuffer, FrameLen);
+ else
+ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
+ MlmeFreeMemory(pAd, pOutBuffer);
+
+ /* ApLogEvent(pAd, pEntry->Addr, EVENT_DISASSOCIATED);*/
+ MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr);
+ }
+}
+
+
+/*
+ ==========================================================================
+ Description:
+ When receiving the last packet of 2-way groupkey handshake.
+ Return:
+ ==========================================================================
+*/
+VOID PeerGroupMsg2Action(
+ IN PRTMP_ADAPTER pAd,
+ IN MAC_TABLE_ENTRY *pEntry,
+ IN VOID *Msg,
+ IN UINT MsgLen)
+{
+ UINT Len;
+ PUCHAR pData;
+ BOOLEAN Cancelled;
+ PEAPOL_PACKET pMsg2;
+ UCHAR group_cipher = Ndis802_11WEPDisabled;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> PeerGroupMsg2Action \n"));
+
+ if ((!pEntry) || !IS_ENTRY_CLIENT(pEntry))
+ return;
+
+ if (MsgLen < (LENGTH_802_1_H + LENGTH_EAPOL_H + MIN_LEN_OF_EAPOL_KEY_MSG))
+ return;
+
+ if (pEntry->WpaState != AS_PTKINITDONE)
+ return;
+
+
+ do
+ {
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ UCHAR apidx = 0;
+
+ if (pEntry->apidx >= pAd->ApCfg.BssidNum)
+ return;
+ else
+ apidx = pEntry->apidx;
+
+ group_cipher = pAd->ApCfg.MBSSID[apidx].GroupKeyWepStatus;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ pData = (PUCHAR)Msg;
+ pMsg2 = (PEAPOL_PACKET) (pData + LENGTH_802_1_H);
+ Len = MsgLen - LENGTH_802_1_H;
+
+ /* Sanity Check peer group message 2 - Replay Counter, MIC*/
+ if (PeerWpaMessageSanity(pAd, pMsg2, Len, EAPOL_GROUP_MSG_2, pEntry) == FALSE)
+ break;
+
+ /* 3. upgrade state*/
+
+ RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
+ pEntry->GTKState = REKEY_ESTABLISHED;
+
+ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
+ {
+ /* send wireless event - for set key done WPA2*/
+ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0);
+
+ DBGPRINT(RT_DEBUG_OFF, ("AP SETKEYS DONE - WPA2, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
+ pEntry->AuthMode, GetAuthMode(pEntry->AuthMode),
+ pEntry->WepStatus, GetEncryptType(pEntry->WepStatus),
+ group_cipher, GetEncryptType(group_cipher)));
+ }
+ else
+ {
+ /* send wireless event - for set key done WPA*/
+ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA1_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0);
+
+ DBGPRINT(RT_DEBUG_OFF, ("AP SETKEYS DONE - WPA1, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
+ pEntry->AuthMode, GetAuthMode(pEntry->AuthMode),
+ pEntry->WepStatus, GetEncryptType(pEntry->WepStatus),
+ group_cipher, GetEncryptType(group_cipher)));
+ }
+ }while(FALSE);
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Classify WPA EAP message type
+
+ Arguments:
+ EAPType Value of EAP message type
+ MsgType Internal Message definition for MLME state machine
+
+ Return Value:
+ TRUE Found appropriate message type
+ FALSE No appropriate message type
+
+ IRQL = DISPATCH_LEVEL
+
+ Note:
+ All these constants are defined in wpa_cmm.h
+ For supplicant, there is only EAPOL Key message avaliable
+
+ ========================================================================
+*/
+BOOLEAN WpaMsgTypeSubst(
+ IN UCHAR EAPType,
+ OUT INT *MsgType)
+{
+ switch (EAPType)
+ {
+ case EAPPacket:
+ *MsgType = MT2_EAPPacket;
+ break;
+ case EAPOLStart:
+ *MsgType = MT2_EAPOLStart;
+ break;
+ case EAPOLLogoff:
+ *MsgType = MT2_EAPOLLogoff;
+ break;
+ case EAPOLKey:
+ *MsgType = MT2_EAPOLKey;
+ break;
+ case EAPOLASFAlert:
+ *MsgType = MT2_EAPOLASFAlert;
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * inc_iv_byte - Increment arbitrary length byte array
+ * @counter: Pointer to byte array
+ * @len: Length of the counter in bytes
+ *
+ * This function increments the least byte of the counter by one and continues
+ * rolling over to more significant bytes if the byte was incremented from
+ * 0xff to 0x00.
+ */
+void inc_iv_byte(UCHAR *iv, UINT len, UINT cnt)
+{
+ int pos = 0;
+ int carry = 0;
+ UCHAR pre_iv;
+
+ while (pos < len)
+ {
+ pre_iv = iv[pos];
+
+ if (carry == 1)
+ iv[pos] ++;
+ else
+ iv[pos] += cnt;
+
+ if (iv[pos] > pre_iv)
+ break;
+
+ carry = 1;
+ pos++;
+ }
+
+ if (pos >= len)
+ DBGPRINT(RT_DEBUG_WARN, ("!!! inc_iv_byte overflow !!!\n"));
+}
+
+
+
+/*
+ ========================================================================
+
+ Routine Description:
+ The pseudo-random function(PRF) that hashes various inputs to
+ derive a pseudo-random value. To add liveness to the pseudo-random
+ value, a nonce should be one of the inputs.
+
+ It is used to generate PTK, GTK or some specific random value.
+
+ Arguments:
+ UCHAR *key, - the key material for HMAC_SHA1 use
+ INT key_len - the length of key
+ UCHAR *prefix - a prefix label
+ INT prefix_len - the length of the label
+ UCHAR *data - a specific data with variable length
+ INT data_len - the length of a specific data
+ INT len - the output lenght
+
+ Return Value:
+ UCHAR *output - the calculated result
+
+ Note:
+ 802.11i-2004 Annex H.3
+
+ ========================================================================
+*/
+VOID PRF(
+ IN UCHAR *key,
+ IN INT key_len,
+ IN UCHAR *prefix,
+ IN INT prefix_len,
+ IN UCHAR *data,
+ IN INT data_len,
+ OUT UCHAR *output,
+ IN INT len)
+{
+ INT i;
+ UCHAR *input;
+ INT currentindex = 0;
+ INT total_len;
+
+ /* Allocate memory for input*/
+ os_alloc_mem(NULL, (PUCHAR *)&input, 1024);
+
+ if (input == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n"));
+ return;
+ }
+
+ /* Generate concatenation input*/
+ NdisMoveMemory(input, prefix, prefix_len);
+
+ /* Concatenate a single octet containing 0*/
+ input[prefix_len] = 0;
+
+ /* Concatenate specific data*/
+ NdisMoveMemory(&input[prefix_len + 1], data, data_len);
+ total_len = prefix_len + 1 + data_len;
+
+ /* Concatenate a single octet containing 0*/
+ /* This octet shall be update later*/
+ input[total_len] = 0;
+ total_len++;
+
+ /* Iterate to calculate the result by hmac-sha-1*/
+ /* Then concatenate to last result*/
+ for (i = 0; i < (len + 19) / 20; i++)
+ {
+ RT_HMAC_SHA1(key, key_len, input, total_len, &output[currentindex], SHA1_DIGEST_SIZE);
+ currentindex += 20;
+
+ /* update the last octet */
+ input[total_len - 1]++;
+ }
+ os_free_mem(NULL, input);
+}
+
+/*
+* F(P, S, c, i) = U1 xor U2 xor ... Uc
+* U1 = PRF(P, S || Int(i))
+* U2 = PRF(P, U1)
+* Uc = PRF(P, Uc-1)
+*/
+
+static void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output)
+{
+ unsigned char digest[36], digest1[SHA1_DIGEST_SIZE];
+ int i, j, len;
+
+ len = strlen(password);
+
+ /* U1 = PRF(P, S || int(i)) */
+ memcpy(digest, ssid, ssidlength);
+ digest[ssidlength] = (unsigned char)((count>>24) & 0xff);
+ digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff);
+ digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff);
+ digest[ssidlength+3] = (unsigned char)(count & 0xff);
+ RT_HMAC_SHA1((unsigned char*) password, len, digest, ssidlength+4, digest1, SHA1_DIGEST_SIZE); /* for WPA update*/
+
+ /* output = U1 */
+ memcpy(output, digest1, SHA1_DIGEST_SIZE);
+ for (i = 1; i < iterations; i++)
+ {
+ /* Un = PRF(P, Un-1) */
+ RT_HMAC_SHA1((unsigned char*) password, len, digest1, SHA1_DIGEST_SIZE, digest, SHA1_DIGEST_SIZE); /* for WPA update*/
+ memcpy(digest1, digest, SHA1_DIGEST_SIZE);
+
+ /* output = output xor Un */
+ for (j = 0; j < SHA1_DIGEST_SIZE; j++)
+ {
+ output[j] ^= digest[j];
+ }
+ }
+}
+
+/*
+* password - ascii string up to 63 characters in length
+* ssid - octet string up to 32 octets
+* ssidlength - length of ssid in octets
+* output must be 40 octets in length and outputs 256 bits of key
+*/
+int RtmpPasswordHash(PSTRING password, PUCHAR ssid, INT ssidlength, PUCHAR output)
+{
+ if ((strlen(password) > 63) || (ssidlength > 32))
+ return 0;
+
+ F(password, ssid, ssidlength, 4096, 1, output);
+ F(password, ssid, ssidlength, 4096, 2, &output[SHA1_DIGEST_SIZE]);
+ return 1;
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ The key derivation function(KDF) is defined in IEEE 802.11r/D9.0, 8.5.1.5.2
+
+ Arguments:
+
+ Return Value:
+
+ Note:
+ Output ¡ö KDF-Length (K, label, Context) where
+ Input: K, a 256-bit key derivation key
+ label, a string identifying the purpose of the keys derived using this KDF
+ Context, a bit string that provides context to identify the derived key
+ Length, the length of the derived key in bits
+ Output: a Length-bit derived key
+
+ result ¡ö ""
+ iterations ¡ö (Length+255)/256
+ do i = 1 to iterations
+ result ¡ö result || HMAC-SHA256(K, i || label || Context || Length)
+ od
+ return first Length bits of result, and securely delete all unused bits
+
+ In this algorithm, i and Length are encoded as 16-bit unsigned integers.
+
+ ========================================================================
+*/
+VOID KDF(
+ IN PUINT8 key,
+ IN INT key_len,
+ IN PUINT8 label,
+ IN INT label_len,
+ IN PUINT8 data,
+ IN INT data_len,
+ OUT PUINT8 output,
+ IN USHORT len)
+{
+ USHORT i;
+ UCHAR *input;
+ INT currentindex = 0;
+ INT total_len;
+ UINT len_in_bits = (len << 3);
+
+ os_alloc_mem(NULL, (PUCHAR *)&input, 1024);
+
+ if (input == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!KDF: no memory!!!\n"));
+ return;
+ }
+
+ NdisZeroMemory(input, 1024);
+
+ /* Initial concatenated value (i || label || Context || Length)*/
+ /* concatenate 16-bit unsigned integer, its initial value is 1. */
+ input[0] = 1;
+ input[1] = 0;
+ total_len = 2;
+
+ /* concatenate a prefix string*/
+ NdisMoveMemory(&input[total_len], label, label_len);
+ total_len += label_len;
+
+ /* concatenate the context*/
+ NdisMoveMemory(&input[total_len], data, data_len);
+ total_len += data_len;
+
+ /* concatenate the length in bits (16-bit unsigned integer)*/
+ input[total_len] = (len_in_bits & 0xFF);
+ input[total_len + 1] = (len_in_bits & 0xFF00) >> 8;
+ total_len += 2;
+
+ for (i = 1; i <= ((len_in_bits + 255) / 256); i++)
+ {
+ /* HMAC-SHA256 derives output */
+ RT_HMAC_SHA256((UCHAR *)key, key_len, input, total_len, (UCHAR *)&output[currentindex], 32);
+
+ currentindex += 32; /* next concatenation location*/
+ input[0]++; /* increment octet count*/
+
+ }
+ os_free_mem(NULL, input);
+}
+
+
+/*
+ ========================================================================
+
+ Routine Description:
+
+ Arguments:
+
+ Return Value:
+
+ Note:
+
+ ========================================================================
+*/
+VOID RTMPDerivePMKID(
+ IN PUINT8 pAaddr,
+ IN PUINT8 pSpaddr,
+ IN PUINT8 pKey,
+ IN PUINT8 pAkm_oui,
+ OUT PUINT8 pPMKID)
+{
+ UCHAR digest[80], text_buf[20];
+ UINT8 text_len;
+
+ /* Concatenate the text for PMKID calculation*/
+ NdisMoveMemory(&text_buf[0], "PMK Name", 8);
+ NdisMoveMemory(&text_buf[8], pAaddr, MAC_ADDR_LEN);
+ NdisMoveMemory(&text_buf[14], pSpaddr, MAC_ADDR_LEN);
+ text_len = 20;
+
+ {
+ RT_HMAC_SHA1(pKey, PMK_LEN, text_buf, text_len, digest, SHA1_DIGEST_SIZE);
+ }
+
+ /* Truncate the first 128-bit of output result */
+ NdisMoveMemory(pPMKID, digest, LEN_PMKID);
+
+}
+
+
+
+/*
+ ========================================================================
+
+ Routine Description:
+ It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK.
+ It shall be called by 4-way handshake processing.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ PMK - pointer to PMK
+ ANonce - pointer to ANonce
+ AA - pointer to Authenticator Address
+ SNonce - pointer to SNonce
+ SA - pointer to Supplicant Address
+ len - indicate the length of PTK (octet)
+
+ Return Value:
+ Output pointer to the PTK
+
+ Note:
+ Refer to IEEE 802.11i-2004 8.5.1.2
+
+ ========================================================================
+*/
+VOID WpaDerivePTK(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR *PMK,
+ IN UCHAR *ANonce,
+ IN UCHAR *AA,
+ IN UCHAR *SNonce,
+ IN UCHAR *SA,
+ OUT UCHAR *output,
+ IN UINT len)
+{
+ UCHAR concatenation[76];
+ UINT CurrPos = 0;
+ UCHAR temp[32];
+ UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ',
+ 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'};
+
+ /* initiate the concatenation input*/
+ NdisZeroMemory(temp, sizeof(temp));
+ NdisZeroMemory(concatenation, 76);
+
+ /* Get smaller address*/
+ if (RTMPCompareMemory(SA, AA, 6) == 1)
+ NdisMoveMemory(concatenation, AA, 6);
+ else
+ NdisMoveMemory(concatenation, SA, 6);
+ CurrPos += 6;
+
+ /* Get larger address*/
+ if (RTMPCompareMemory(SA, AA, 6) == 1)
+ NdisMoveMemory(&concatenation[CurrPos], SA, 6);
+ else
+ NdisMoveMemory(&concatenation[CurrPos], AA, 6);
+
+ /* store the larger mac address for backward compatible of */
+ /* ralink proprietary STA-key issue */
+ NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN);
+ CurrPos += 6;
+
+ /* Get smaller Nonce*/
+ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
+ NdisMoveMemory(&concatenation[CurrPos], temp, 32); /* patch for ralink proprietary STA-key issue*/
+ else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
+ NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
+ else
+ NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
+ CurrPos += 32;
+
+ /* Get larger Nonce*/
+ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
+ NdisMoveMemory(&concatenation[CurrPos], temp, 32); /* patch for ralink proprietary STA-key issue*/
+ else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
+ NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
+ else
+ NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
+ CurrPos += 32;
+
+ hex_dump("PMK", PMK, LEN_PMK);
+ hex_dump("concatenation=", concatenation, 76);
+
+ /* Use PRF to generate PTK*/
+ PRF(PMK, LEN_PMK, Prefix, 22, concatenation, 76, output, len);
+
+}
+
+VOID WpaDeriveGTK(
+ IN UCHAR *GMK,
+ IN UCHAR *GNonce,
+ IN UCHAR *AA,
+ OUT UCHAR *output,
+ IN UINT len)
+{
+ UCHAR concatenation[76];
+ UINT CurrPos=0;
+ UCHAR Prefix[19];
+ UCHAR temp[80];
+
+ NdisMoveMemory(&concatenation[CurrPos], AA, 6);
+ CurrPos += 6;
+
+ NdisMoveMemory(&concatenation[CurrPos], GNonce , 32);
+ CurrPos += 32;
+
+ Prefix[0] = 'G';
+ Prefix[1] = 'r';
+ Prefix[2] = 'o';
+ Prefix[3] = 'u';
+ Prefix[4] = 'p';
+ Prefix[5] = ' ';
+ Prefix[6] = 'k';
+ Prefix[7] = 'e';
+ Prefix[8] = 'y';
+ Prefix[9] = ' ';
+ Prefix[10] = 'e';
+ Prefix[11] = 'x';
+ Prefix[12] = 'p';
+ Prefix[13] = 'a';
+ Prefix[14] = 'n';
+ Prefix[15] = 's';
+ Prefix[16] = 'i';
+ Prefix[17] = 'o';
+ Prefix[18] = 'n';
+
+ PRF(GMK, PMK_LEN, Prefix, 19, concatenation, 38 , temp, len);
+ NdisMoveMemory(output, temp, len);
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Generate random number by software.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ macAddr - pointer to local MAC address
+
+ Return Value:
+
+ Note:
+ 802.1ii-2004 Annex H.5
+
+ ========================================================================
+*/
+VOID GenRandom(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR *macAddr,
+ OUT UCHAR *random)
+{
+ INT i, curr;
+ UCHAR local[80], KeyCounter[32];
+ UCHAR result[80];
+ ULONG CurrentTime;
+ UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'};
+
+ /* Zero the related information*/
+ NdisZeroMemory(result, 80);
+ NdisZeroMemory(local, 80);
+ NdisZeroMemory(KeyCounter, 32);
+
+ for (i = 0; i < 32; i++)
+ {
+ /* copy the local MAC address*/
+ COPY_MAC_ADDR(local, macAddr);
+ curr = MAC_ADDR_LEN;
+
+ /* concatenate the current time*/
+ NdisGetSystemUpTime(&CurrentTime);
+ NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime));
+ curr += sizeof(CurrentTime);
+
+ /* concatenate the last result*/
+ NdisMoveMemory(&local[curr], result, 32);
+ curr += 32;
+
+ /* concatenate a variable */
+ NdisMoveMemory(&local[curr], &i, 2);
+ curr += 2;
+
+ /* calculate the result*/
+ PRF(KeyCounter, 32, prefix,12, local, curr, result, 32);
+ }
+
+ NdisMoveMemory(random, result, 32);
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Build cipher suite in RSN-IE.
+ It only shall be called by RTMPMakeRSNIE.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ ElementID - indicate the WPA1 or WPA2
+ WepStatus - indicate the encryption type
+ bMixCipher - a boolean to indicate the pairwise cipher and group
+ cipher are the same or not
+
+ Return Value:
+
+ Note:
+
+ ========================================================================
+*/
+static VOID RTMPMakeRsnIeCipher(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR ElementID,
+ IN UINT WepStatus,
+ IN UCHAR apidx,
+ IN BOOLEAN bMixCipher,
+ IN UCHAR FlexibleCipher,
+ OUT PUCHAR pRsnIe,
+ OUT UCHAR *rsn_len)
+{
+ UCHAR PairwiseCnt;
+
+ *rsn_len = 0;
+
+ /* decide WPA2 or WPA1 */
+ if (ElementID == Wpa2Ie)
+ {
+ RSNIE2 *pRsnie_cipher = (RSNIE2*)pRsnIe;
+
+ /* Assign the verson as 1*/
+ pRsnie_cipher->version = 1;
+
+ switch (WepStatus)
+ {
+ /* TKIP mode*/
+ case Ndis802_11Encryption2Enabled:
+ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
+ pRsnie_cipher->ucount = 1;
+ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4);
+ *rsn_len = sizeof(RSNIE2);
+ break;
+
+ /* AES mode*/
+ case Ndis802_11Encryption3Enabled:
+ if (bMixCipher)
+ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
+ else
+ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4);
+ pRsnie_cipher->ucount = 1;
+ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4);
+ *rsn_len = sizeof(RSNIE2);
+ break;
+
+ /* TKIP-AES mix mode*/
+ case Ndis802_11Encryption4Enabled:
+ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
+
+ PairwiseCnt = 1;
+ /* Insert WPA2 TKIP as the first pairwise cipher */
+ if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher))
+ {
+ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4);
+ /* Insert WPA2 AES as the secondary pairwise cipher*/
+ if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher))
+ {
+ NdisMoveMemory(pRsnIe + sizeof(RSNIE2), OUI_WPA2_CCMP, 4);
+ PairwiseCnt = 2;
+ }
+ }
+ else
+ {
+ /* Insert WPA2 AES as the first pairwise cipher */
+ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4);
+ }
+
+ pRsnie_cipher->ucount = PairwiseCnt;
+ *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1));
+ break;
+ }
+
+
+ /* swap for big-endian platform*/
+ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
+ pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
+ }
+ else
+ {
+ RSNIE *pRsnie_cipher = (RSNIE*)pRsnIe;
+
+ /* Assign OUI and version*/
+ NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4);
+ pRsnie_cipher->version = 1;
+
+ switch (WepStatus)
+ {
+ /* TKIP mode*/
+ case Ndis802_11Encryption2Enabled:
+ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
+ pRsnie_cipher->ucount = 1;
+ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4);
+ *rsn_len = sizeof(RSNIE);
+ break;
+
+ /* AES mode*/
+ case Ndis802_11Encryption3Enabled:
+ if (bMixCipher)
+ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
+ else
+ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4);
+ pRsnie_cipher->ucount = 1;
+ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4);
+ *rsn_len = sizeof(RSNIE);
+ break;
+
+ /* TKIP-AES mix mode*/
+ case Ndis802_11Encryption4Enabled:
+ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
+
+ PairwiseCnt = 1;
+ /* Insert WPA TKIP as the first pairwise cipher */
+ if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher))
+ {
+ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4);
+ /* Insert WPA AES as the secondary pairwise cipher*/
+ if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher))
+ {
+ NdisMoveMemory(pRsnIe + sizeof(RSNIE), OUI_WPA_CCMP, 4);
+ PairwiseCnt = 2;
+ }
+ }
+ else
+ {
+ /* Insert WPA AES as the first pairwise cipher */
+ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4);
+ }
+
+ pRsnie_cipher->ucount = PairwiseCnt;
+ *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1));
+ break;
+ }
+
+
+ /* swap for big-endian platform*/
+ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
+ pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
+ }
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Build AKM suite in RSN-IE.
+ It only shall be called by RTMPMakeRSNIE.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ ElementID - indicate the WPA1 or WPA2
+ AuthMode - indicate the authentication mode
+ apidx - indicate the interface index
+
+ Return Value:
+
+ Note:
+
+ ========================================================================
+*/
+static VOID RTMPMakeRsnIeAKM(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR ElementID,
+ IN UINT AuthMode,
+ IN UCHAR apidx,
+ OUT PUCHAR pRsnIe,
+ OUT UCHAR *rsn_len)
+{
+ RSNIE_AUTH *pRsnie_auth;
+ UCHAR AkmCnt = 1; /* default as 1*/
+
+ pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len));
+
+ /* decide WPA2 or WPA1 */
+ if (ElementID == Wpa2Ie)
+ {
+
+ switch (AuthMode)
+ {
+ case Ndis802_11AuthModeWPA2:
+ case Ndis802_11AuthModeWPA1WPA2:
+ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4);
+
+ break;
+
+ case Ndis802_11AuthModeWPA2PSK:
+ case Ndis802_11AuthModeWPA1PSKWPA2PSK:
+ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4);
+
+ break;
+ default:
+ AkmCnt = 0;
+ break;
+
+ }
+ }
+ else
+ {
+ switch (AuthMode)
+ {
+ case Ndis802_11AuthModeWPA:
+ case Ndis802_11AuthModeWPA1WPA2:
+ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4);
+ break;
+
+ case Ndis802_11AuthModeWPAPSK:
+ case Ndis802_11AuthModeWPA1PSKWPA2PSK:
+ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4);
+ break;
+
+ case Ndis802_11AuthModeWPANone:
+ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4);
+ break;
+ default:
+ AkmCnt = 0;
+ break;
+ }
+ }
+
+ pRsnie_auth->acount = AkmCnt;
+ pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount);
+
+ /* update current RSNIE length*/
+ (*rsn_len) += (sizeof(RSNIE_AUTH) + (4 * (AkmCnt - 1)));
+
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Build capability in RSN-IE.
+ It only shall be called by RTMPMakeRSNIE.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ ElementID - indicate the WPA1 or WPA2
+ apidx - indicate the interface index
+
+ Return Value:
+
+ Note:
+
+ ========================================================================
+*/
+static VOID RTMPMakeRsnIeCap(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR ElementID,
+ IN UCHAR apidx,
+ OUT PUCHAR pRsnIe,
+ OUT UCHAR *rsn_len)
+{
+ RSN_CAPABILITIES *pRSN_Cap;
+
+ /* it could be ignored in WPA1 mode*/
+ if (ElementID == WpaIe)
+ return;
+
+ pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len));
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ if (apidx < pAd->ApCfg.BssidNum)
+ {
+ PMULTISSID_STRUCT pMbss = &pAd->ApCfg.MBSSID[apidx];
+
+#ifdef DOT1X_SUPPORT
+ pRSN_Cap->field.PreAuth = (pMbss->PreAuth == TRUE) ? 1 : 0;
+#endif /* DOT1X_SUPPORT */
+ }
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+
+ pRSN_Cap->word = cpu2le16(pRSN_Cap->word);
+
+ (*rsn_len) += sizeof(RSN_CAPABILITIES); /* update current RSNIE length*/
+
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Build PMKID in RSN-IE.
+ It only shall be called by RTMPMakeRSNIE.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ ElementID - indicate the WPA1 or WPA2
+ apidx - indicate the interface index
+
+ Return Value:
+
+ Note:
+
+ ========================================================================
+*/
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Build RSN IE context. It is not included element-ID and length.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ AuthMode - indicate the authentication mode
+ WepStatus - indicate the encryption type
+ apidx - indicate the interface index
+
+ Return Value:
+
+ Note:
+
+ ========================================================================
+*/
+VOID RTMPMakeRSNIE(
+ IN PRTMP_ADAPTER pAd,
+ IN UINT AuthMode,
+ IN UINT WepStatus,
+ IN UCHAR apidx)
+{
+ PUCHAR pRsnIe = NULL; /* primary RSNIE*/
+ UCHAR *rsnielen_cur_p = 0; /* the length of the primary RSNIE */
+#ifdef CONFIG_AP_SUPPORT
+ PUCHAR pRsnIe_ex = NULL; /* secondary RSNIE, it's ONLY used in WPA-mix mode */
+ BOOLEAN bMixRsnIe = FALSE; /* indicate WPA-mix mode is on or off*/
+ UCHAR s_offset;
+#endif /* CONFIG_AP_SUPPORT */
+ UCHAR *rsnielen_ex_cur_p = 0; /* the length of the secondary RSNIE */
+ UCHAR PrimaryRsnie;
+ BOOLEAN bMixCipher = FALSE; /* indicate the pairwise and group cipher are different*/
+ UCHAR p_offset;
+ WPA_MIX_PAIR_CIPHER FlexibleCipher = MIX_CIPHER_NOTUSE; /* it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode*/
+
+ rsnielen_cur_p = NULL;
+ rsnielen_ex_cur_p = NULL;
+
+ do
+ {
+
+#ifdef APCLI_SUPPORT
+ if (apidx >= MIN_NET_DEVICE_FOR_APCLI)
+ {
+ UINT apcliIfidx = 0;
+
+ /* Only support WPAPSK or WPA2PSK for AP-Client mode */
+#ifdef APCLI_WPA_SUPPLICANT_SUPPORT
+ if (pAd->ApCfg.ApCliTab[apcliIfidx].WpaSupplicantUP != WPA_SUPPLICANT_DISABLE)
+ {
+ if (AuthMode < Ndis802_11AuthModeWPA)
+ return;
+ }
+ else
+#endif /* APCLI_WPA_SUPPLICANT_SUPPORT */
+ {
+
+ if ((AuthMode != Ndis802_11AuthModeWPAPSK) &&
+ (AuthMode != Ndis802_11AuthModeWPA2PSK))
+ return;
+
+ }
+
+ DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(ApCli)\n"));
+
+ apcliIfidx = apidx - MIN_NET_DEVICE_FOR_APCLI;
+
+ /* Initiate some related information */
+ if (apcliIfidx < MAX_APCLI_NUM)
+ {
+ pAd->ApCfg.ApCliTab[apcliIfidx].RSNIE_Len = 0;
+ NdisZeroMemory(pAd->ApCfg.ApCliTab[apcliIfidx].RSN_IE, MAX_LEN_OF_RSNIE);
+ rsnielen_cur_p = &pAd->ApCfg.ApCliTab[apcliIfidx].RSNIE_Len;
+ pRsnIe = pAd->ApCfg.ApCliTab[apcliIfidx].RSN_IE;
+
+ bMixCipher = pAd->ApCfg.ApCliTab[apcliIfidx].bMixCipher;
+ break;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("RTMPMakeRSNIE: invalid apcliIfidx(%d)\n", apcliIfidx));
+ return;
+ }
+ }
+#endif /* APCLI_SUPPORT */
+
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+ /* Sanity check for apidx */
+ MBSS_MR_APIDX_SANITY_CHECK(pAd, apidx);
+#ifdef HOSTAPD_SUPPORT
+ if(pAd->ApCfg.MBSSID[apidx].Hostapd)
+ return;
+#endif /* HOSTAPD_SUPPORT */
+ if ((AuthMode != Ndis802_11AuthModeWPA) &&
+ (AuthMode != Ndis802_11AuthModeWPAPSK) &&
+ (AuthMode != Ndis802_11AuthModeWPA2) &&
+ (AuthMode != Ndis802_11AuthModeWPA2PSK) &&
+ (AuthMode != Ndis802_11AuthModeWPA1WPA2) &&
+ (AuthMode != Ndis802_11AuthModeWPA1PSKWPA2PSK)
+#ifdef WAPI_SUPPORT
+ && (AuthMode != Ndis802_11AuthModeWAICERT)
+ && (AuthMode != Ndis802_11AuthModeWAIPSK)
+#endif /* WAPI_SUPPORT */
+ )
+ return;
+
+ DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(AP-ra%d)\n", apidx));
+
+ /* decide the group key encryption type */
+ if (WepStatus == Ndis802_11Encryption4Enabled)
+ {
+ pAd->ApCfg.MBSSID[apidx].GroupKeyWepStatus = Ndis802_11Encryption2Enabled;
+ FlexibleCipher = pAd->ApCfg.MBSSID[apidx].WpaMixPairCipher;
+ }
+ else
+ pAd->ApCfg.MBSSID[apidx].GroupKeyWepStatus = WepStatus;
+
+ /* Initiate some related information */
+ pAd->ApCfg.MBSSID[apidx].RSNIE_Len[0] = 0;
+ pAd->ApCfg.MBSSID[apidx].RSNIE_Len[1] = 0;
+ NdisZeroMemory(pAd->ApCfg.MBSSID[apidx].RSN_IE[0], MAX_LEN_OF_RSNIE);
+ NdisZeroMemory(pAd->ApCfg.MBSSID[apidx].RSN_IE[1], MAX_LEN_OF_RSNIE);
+
+ /* Pointer to the first RSNIE context */
+ rsnielen_cur_p = &pAd->ApCfg.MBSSID[apidx].RSNIE_Len[0];
+ pRsnIe = pAd->ApCfg.MBSSID[apidx].RSN_IE[0];
+
+ /* Pointer to the secondary RSNIE context */
+ rsnielen_ex_cur_p = &pAd->ApCfg.MBSSID[apidx].RSNIE_Len[1];
+ pRsnIe_ex = pAd->ApCfg.MBSSID[apidx].RSN_IE[1];
+
+ /* Decide whether the authentication mode is WPA1-WPA2 mixed mode */
+ if ((AuthMode == Ndis802_11AuthModeWPA1WPA2) ||
+ (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK))
+ {
+ bMixRsnIe = TRUE;
+ }
+ break;
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+ } while(FALSE);
+
+ /* indicate primary RSNIE as WPA or WPA2*/
+ if ((AuthMode == Ndis802_11AuthModeWPA) ||
+ (AuthMode == Ndis802_11AuthModeWPAPSK) ||
+ (AuthMode == Ndis802_11AuthModeWPANone) ||
+ (AuthMode == Ndis802_11AuthModeWPA1WPA2) ||
+ (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK))
+ PrimaryRsnie = WpaIe;
+#ifdef WAPI_SUPPORT
+ else if ((AuthMode == Ndis802_11AuthModeWAICERT) ||
+ (AuthMode == Ndis802_11AuthModeWAIPSK))
+ PrimaryRsnie = WapiIe;
+#endif /* WAPI_SUPPORT */
+ else
+ PrimaryRsnie = Wpa2Ie;
+
+#ifdef WAPI_SUPPORT
+ if (PrimaryRsnie == WapiIe)
+ {
+ RTMPInsertWapiIe(AuthMode, WepStatus, pRsnIe, &p_offset);
+ }
+ else
+#endif /* WAPI_SUPPORT */
+ {
+ /* Build the primary RSNIE*/
+ /* 1. insert cipher suite*/
+ RTMPMakeRsnIeCipher(pAd, PrimaryRsnie, WepStatus, apidx, bMixCipher, FlexibleCipher, pRsnIe, &p_offset);
+
+ /* 2. insert AKM*/
+ RTMPMakeRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset);
+
+ /* 3. insert capability*/
+ RTMPMakeRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset);
+
+ }
+
+ /* 4. update the RSNIE length*/
+ if (rsnielen_cur_p == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: rsnielen_cur_p == NULL!\n", __FUNCTION__));
+ return;
+ }
+
+ *rsnielen_cur_p = p_offset;
+
+ hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p));
+
+#ifdef CONFIG_AP_SUPPORT
+ if ((pAd->OpMode == OPMODE_AP)
+ )
+ {
+ /* if necessary, build the secondary RSNIE*/
+ if (bMixRsnIe)
+ {
+ /* 1. insert cipher suite*/
+ RTMPMakeRsnIeCipher(pAd, Wpa2Ie, WepStatus, apidx, bMixCipher, FlexibleCipher, pRsnIe_ex, &s_offset);
+
+ /* 2. insert AKM*/
+ RTMPMakeRsnIeAKM(pAd, Wpa2Ie, AuthMode, apidx, pRsnIe_ex, &s_offset);
+
+ /* 3. insert capability*/
+ RTMPMakeRsnIeCap(pAd, Wpa2Ie, apidx, pRsnIe_ex, &s_offset);
+
+
+ /* Update the RSNIE length*/
+ *rsnielen_ex_cur_p = s_offset;
+
+ hex_dump("The secondary RSNIE", pRsnIe_ex, (*rsnielen_ex_cur_p));
+ }
+ }
+#endif /* CONFIG_AP_SUPPORT */
+
+}
+
+/*
+ ==========================================================================
+ Description:
+ Check whether the received frame is EAP frame.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ pEntry - pointer to active entry
+ pData - the received frame
+ DataByteCount - the received frame's length
+ FromWhichBSSID - indicate the interface index
+
+ Return:
+ TRUE - This frame is EAP frame
+ FALSE - otherwise
+ ==========================================================================
+*/
+BOOLEAN RTMPCheckWPAframe(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PUCHAR pData,
+ IN ULONG DataByteCount,
+ IN UCHAR FromWhichBSSID)
+{
+ ULONG Body_len;
+ BOOLEAN Cancelled;
+
+ do
+ {
+ } while (FALSE);
+
+ if(DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H))
+ return FALSE;
+
+
+ /* Skip LLC header */
+ if (NdisEqualMemory(SNAP_802_1H, pData, 6) ||
+ /* Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL*/
+ NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6))
+ {
+ pData += 6;
+ }
+ /* Skip 2-bytes EAPoL type */
+ if (NdisEqualMemory(EAPOL, pData, 2))
+/* if (*(UINT16 *)EAPOL == *(UINT16 *)pData)*/
+ {
+ pData += 2;
+ }
+ else
+ return FALSE;
+
+ switch (*(pData+1))
+ {
+ case EAPPacket:
+ Body_len = (*(pData+2)<<8) | (*(pData+3));
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef IDS_SUPPORT
+ if((*(pData+4)) == EAP_CODE_REQUEST)
+ pAd->ApCfg.RcvdEapReqCount ++;
+#endif /* IDS_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len));
+ break;
+ case EAPOLStart:
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n"));
+ if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n"));
+ RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled);
+ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE;
+ }
+ break;
+ case EAPOLLogoff:
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n"));
+ break;
+ case EAPOLKey:
+ Body_len = (*(pData+2)<<8) | (*(pData+3));
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len));
+ break;
+ case EAPOLASFAlert:
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n"));
+ break;
+ default:
+ return FALSE;
+
+ }
+ return TRUE;
+}
+
+
+#ifdef HDR_TRANS_SUPPORT
+BOOLEAN RTMPCheckWPAframe_Hdr_Trns(
+ IN PRTMP_ADAPTER pAd,
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN PUCHAR pData,
+ IN ULONG DataByteCount,
+ IN UCHAR FromWhichBSSID)
+{
+ ULONG Body_len;
+ BOOLEAN Cancelled;
+
+ do
+ {
+ } while (FALSE);
+
+ if(DataByteCount < (LENGTH_802_3 + LENGTH_EAPOL_H))
+ return FALSE;
+
+
+ /* Skip LLC header */
+
+ pData += LENGTH_802_3;
+
+ /* Skip 2-bytes EAPoL type */
+ if (NdisEqualMemory(EAPOL, pData, 2))
+/* if (*(UINT16 *)EAPOL == *(UINT16 *)pData)*/
+ {
+ pData += 2;
+ }
+ else
+ return FALSE;
+
+ switch (*(pData+1))
+ {
+ case EAPPacket:
+ Body_len = (*(pData+2)<<8) | (*(pData+3));
+#ifdef CONFIG_AP_SUPPORT
+ IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
+ {
+#ifdef IDS_SUPPORT
+ if((*(pData+4)) == EAP_CODE_REQUEST)
+ pAd->ApCfg.RcvdEapReqCount ++;
+#endif /* IDS_SUPPORT */
+ }
+#endif /* CONFIG_AP_SUPPORT */
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len));
+ break;
+ case EAPOLStart:
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n"));
+ if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n"));
+ RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled);
+ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE;
+ }
+ break;
+ case EAPOLLogoff:
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n"));
+ break;
+ case EAPOLKey:
+ Body_len = (*(pData+2)<<8) | (*(pData+3));
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len));
+ break;
+ case EAPOLASFAlert:
+ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n"));
+ break;
+ default:
+ return FALSE;
+
+ }
+ return TRUE;
+}
+#endif /* HDR_TRANS_SUPPORT */
+
+
+/*
+ ==========================================================================
+ Description:
+ Report the EAP message type
+
+ Arguments:
+ msg - EAPOL_PAIR_MSG_1
+ EAPOL_PAIR_MSG_2
+ EAPOL_PAIR_MSG_3
+ EAPOL_PAIR_MSG_4
+ EAPOL_GROUP_MSG_1
+ EAPOL_GROUP_MSG_2
+
+ Return:
+ message type string
+
+ ==========================================================================
+*/
+PSTRING GetEapolMsgType(CHAR msg)
+{
+ if(msg == EAPOL_PAIR_MSG_1)
+ return "Pairwise Message 1";
+ else if(msg == EAPOL_PAIR_MSG_2)
+ return "Pairwise Message 2";
+ else if(msg == EAPOL_PAIR_MSG_3)
+ return "Pairwise Message 3";
+ else if(msg == EAPOL_PAIR_MSG_4)
+ return "Pairwise Message 4";
+ else if(msg == EAPOL_GROUP_MSG_1)
+ return "Group Message 1";
+ else if(msg == EAPOL_GROUP_MSG_2)
+ return "Group Message 2";
+ else
+ return "Invalid Message";
+}
+
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Check Sanity RSN IE of EAPoL message
+
+ Arguments:
+
+ Return Value:
+
+
+ ========================================================================
+*/
+BOOLEAN RTMPCheckRSNIE(
+ IN PRTMP_ADAPTER pAd,
+ IN PUCHAR pData,
+ IN UCHAR DataLen,
+ IN MAC_TABLE_ENTRY *pEntry,
+ OUT UCHAR *Offset)
+{
+ PUCHAR pVIE;
+ UCHAR len;
+ PEID_STRUCT pEid;
+ BOOLEAN result = FALSE;
+
+ pVIE = pData;
+ len = DataLen;
+ *Offset = 0;
+
+ while (len > sizeof(RSNIE2))
+ {
+ pEid = (PEID_STRUCT) pVIE;
+ /* WPA RSN IE*/
+ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)))
+ {
+ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) &&
+ (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) &&
+ (pEntry->RSNIE_Len == (pEid->Len + 2)))
+ {
+ result = TRUE;
+ }
+
+ *Offset += (pEid->Len + 2);
+ }
+ /* WPA2 RSN IE, doesn't need to check RSNIE Capabilities field */
+ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)))
+ {
+ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2 || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) &&
+ (pEid->Eid == pEntry->RSN_IE[0]) &&
+ ((pEid->Len + 2) >= pEntry->RSNIE_Len) &&
+ (NdisEqualMemory(pEid->Octet, &pEntry->RSN_IE[2], pEntry->RSNIE_Len - 4)))
+ {
+
+ result = TRUE;
+ }
+
+ *Offset += (pEid->Len + 2);
+ }
+ else
+ {
+ break;
+ }
+
+ pVIE += (pEid->Len + 2);
+ len -= (pEid->Len + 2);
+ }
+
+
+ return result;
+
+}
+
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK.
+ GTK is encaptulated in KDE format at p.83 802.11i D10
+
+ Arguments:
+
+ Return Value:
+
+ Note:
+ 802.11i D10
+
+ ========================================================================
+*/
+BOOLEAN RTMPParseEapolKeyData(
+ IN PRTMP_ADAPTER pAd,
+ IN PUCHAR pKeyData,
+ IN UCHAR KeyDataLen,
+ IN UCHAR GroupKeyIndex,
+ IN UCHAR MsgType,
+ IN BOOLEAN bWPA2,
+ IN MAC_TABLE_ENTRY *pEntry)
+{
+ PUCHAR pMyKeyData = pKeyData;
+ UCHAR KeyDataLength = KeyDataLen;
+ UCHAR GTK[MAX_LEN_GTK];
+ UCHAR GTKLEN = 0;
+ UCHAR DefaultIdx = 0;
+ UCHAR skip_offset = 0;
+
+
+ NdisZeroMemory(GTK, MAX_LEN_GTK);
+
+ /* Verify The RSN IE contained in pairewise_msg_2 && pairewise_msg_3 and skip it*/
+ if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_3)
+ {
+ {
+ if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3)
+ {
+ /*WpaShowAllsuite(pMyKeyData, skip_offset);*/
+
+ /* skip RSN IE*/
+ pMyKeyData += skip_offset;
+ KeyDataLength -= skip_offset;
+ DBGPRINT(RT_DEBUG_TRACE, ("RTMPParseEapolKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset));
+ }
+ else
+ return TRUE;
+ }
+ }
+
+ DBGPRINT(RT_DEBUG_TRACE,("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength));
+ /*hex_dump("remain data", pMyKeyData, KeyDataLength);*/
+
+
+ /* Parse KDE format in pairwise_msg_3_WPA2 && group_msg_1_WPA2*/
+ if (bWPA2 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1))
+ {
+ PEID_STRUCT pEid;
+
+ pEid = (PEID_STRUCT) pMyKeyData;
+ skip_offset = 0;
+ while ((skip_offset + 2 + pEid->Len) <= KeyDataLength)
+ {
+ switch(pEid->Eid)
+ {
+ case WPA_KDE_TYPE:
+ {
+ PKDE_HDR pKDE;
+
+ pKDE = (PKDE_HDR)pEid;
+ if (NdisEqualMemory(pKDE->OUI, OUI_WPA2, 3))
+ {
+ if (pKDE->DataType == KDE_GTK)
+ {
+ PGTK_KDE pKdeGtk;
+
+ pKdeGtk = (PGTK_KDE) &pKDE->octet[0];
+ DefaultIdx = pKdeGtk->Kid;
+
+ /* Get GTK length - refer to IEEE 802.11i-2004 p.82 */
+ GTKLEN = pKDE->Len -6;
+ if (GTKLEN < LEN_WEP64)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN));
+ return FALSE;
+ }
+ NdisMoveMemory(GTK, pKdeGtk->GTK, GTKLEN);
+ DBGPRINT(RT_DEBUG_TRACE, ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n", DefaultIdx, GTKLEN));
+ }
+ }
+ }
+ break;
+ }
+ skip_offset = skip_offset + 2 + pEid->Len;
+ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len);
+ }
+
+ /* skip KDE Info*/
+ pMyKeyData += skip_offset;
+ KeyDataLength -= skip_offset;
+ }
+ else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1)
+ {
+ DefaultIdx = GroupKeyIndex;
+ GTKLEN = KeyDataLength;
+ NdisMoveMemory(GTK, pMyKeyData, KeyDataLength);
+ DBGPRINT(RT_DEBUG_TRACE, ("GTK without KDE, DefaultKeyID=%d, KeyLen=%d \n", DefaultIdx, GTKLEN));
+ }
+
+ /* Sanity check - shared key index must be 0 ~ 3*/
+ if (DefaultIdx > 3)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index(%d) is invalid in %s %s \n", DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType)));
+ return FALSE;
+ }
+
+#ifdef CONFIG_AP_SUPPORT
+#ifdef APCLI_SUPPORT
+ if (IS_ENTRY_APCLI(pEntry))
+ {
+ /* Set Group key material, TxMic and RxMic for AP-Client*/
+ if (!APCliInstallSharedKey(pAd, GTK, GTKLEN, DefaultIdx, pEntry))
+ {
+ return FALSE;
+ }
+ }
+#endif /* APCLI_SUPPORT */
+#endif /* CONFIG_AP_SUPPORT */
+
+
+ return TRUE;
+
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Construct KDE common format
+ Its format is below,
+
+ +--------------------+
+ | Type (0xdd) | 1 octet
+ +--------------------+
+ | Length | 1 octet
+ +--------------------+
+ | OUI | 3 octets
+ +--------------------+
+ | Data Type | 1 octet
+ +--------------------+
+
+ Arguments:
+
+ Return Value:
+
+ Note:
+ It's defined in IEEE 802.11-2007 Figure 8-25.
+
+ ========================================================================
+*/
+VOID WPA_ConstructKdeHdr(
+ IN UINT8 data_type,
+ IN UINT8 data_len,
+ OUT PUCHAR pBuf)
+{
+ PKDE_HDR pHdr;
+
+ pHdr = (PKDE_HDR)pBuf;
+
+ NdisZeroMemory(pHdr, sizeof(KDE_HDR));
+
+ pHdr->Type = WPA_KDE_TYPE;
+
+ /* The Length field specifies the number of octets in the OUI, Data
+ Type, and Data fields. */
+ pHdr->Len = 4 + data_len;
+
+ NdisMoveMemory(pHdr->OUI, OUI_WPA2, 3);
+ pHdr->DataType = data_type;
+
+}
+
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Construct EAPoL message for WPA handshaking
+ Its format is below,
+
+ +--------------------+
+ | Protocol Version | 1 octet
+ +--------------------+
+ | Protocol Type | 1 octet
+ +--------------------+
+ | Body Length | 2 octets
+ +--------------------+
+ | Descriptor Type | 1 octet
+ +--------------------+
+ | Key Information | 2 octets
+ +--------------------+
+ | Key Length | 1 octet
+ +--------------------+
+ | Key Repaly Counter | 8 octets
+ +--------------------+
+ | Key Nonce | 32 octets
+ +--------------------+
+ | Key IV | 16 octets
+ +--------------------+
+ | Key RSC | 8 octets
+ +--------------------+
+ | Key ID or Reserved | 8 octets
+ +--------------------+
+ | Key MIC | 16 octets
+ +--------------------+
+ | Key Data Length | 2 octets
+ +--------------------+
+ | Key Data | n octets
+ +--------------------+
+
+
+ Arguments:
+ pAd Pointer to our adapter
+
+ Return Value:
+ None
+
+ Note:
+
+ ========================================================================
+*/
+VOID ConstructEapolMsg(
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN UCHAR GroupKeyWepStatus,
+ IN UCHAR MsgType,
+ IN UCHAR DefaultKeyIdx,
+ IN UCHAR *KeyNonce,
+ IN UCHAR *TxRSC,
+ IN UCHAR *GTK,
+ IN UCHAR *RSNIE,
+ IN UCHAR RSNIE_Len,
+ OUT PEAPOL_PACKET pMsg)
+{
+ BOOLEAN bWPA2 = FALSE;
+ UCHAR KeyDescVer;
+
+ /* Choose WPA2 or not*/
+ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) ||
+ (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
+ bWPA2 = TRUE;
+
+ /* Init Packet and Fill header */
+ pMsg->ProVer = EAPOL_VER;
+ pMsg->ProType = EAPOLKey;
+
+ /* Default 95 bytes, the EAPoL-Key descriptor exclude Key-data field*/
+ SET_UINT16_TO_ARRARY(pMsg->Body_Len, MIN_LEN_OF_EAPOL_KEY_MSG);
+
+ /* Fill in EAPoL descriptor*/
+ if (bWPA2)
+ pMsg->KeyDesc.Type = WPA2_KEY_DESC;
+ else
+ pMsg->KeyDesc.Type = WPA1_KEY_DESC;
+
+ /* Key Descriptor Version (bits 0-2) specifies the key descriptor version type*/
+ {
+ /* Fill in Key information, refer to IEEE Std 802.11i-2004 page 78 */
+ /* When either the pairwise or the group cipher is AES, the KEY_DESC_AES shall be used.*/
+ KeyDescVer = (((pEntry->WepStatus == Ndis802_11Encryption3Enabled) ||
+ (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)) ? (KEY_DESC_AES) : (KEY_DESC_TKIP));
+ }
+
+ pMsg->KeyDesc.KeyInfo.KeyDescVer = KeyDescVer;
+
+ /* Specify Key Type as Group(0) or Pairwise(1)*/
+ if (MsgType >= EAPOL_GROUP_MSG_1)
+ pMsg->KeyDesc.KeyInfo.KeyType = GROUPKEY;
+ else
+ pMsg->KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
+
+ /* Specify Key Index, only group_msg1_WPA1*/
+ if (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))
+ pMsg->KeyDesc.KeyInfo.KeyIndex = DefaultKeyIdx;
+
+ if (MsgType == EAPOL_PAIR_MSG_3)
+ pMsg->KeyDesc.KeyInfo.Install = 1;
+
+ if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))
+ pMsg->KeyDesc.KeyInfo.KeyAck = 1;
+
+ if (MsgType != EAPOL_PAIR_MSG_1)
+ pMsg->KeyDesc.KeyInfo.KeyMic = 1;
+
+ if ((bWPA2 && (MsgType >= EAPOL_PAIR_MSG_3)) ||
+ (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1)))
+ {
+ pMsg->KeyDesc.KeyInfo.Secure = 1;
+ }
+
+ /* This subfield shall be set, and the Key Data field shall be encrypted, if
+ any key material (e.g., GTK or SMK) is included in the frame. */
+ if (bWPA2 && ((MsgType == EAPOL_PAIR_MSG_3) ||
+ (MsgType == EAPOL_GROUP_MSG_1)))
+ {
+ pMsg->KeyDesc.KeyInfo.EKD_DL = 1;
+ }
+
+ /* key Information element has done. */
+ *(USHORT *)(&pMsg->KeyDesc.KeyInfo) = cpu2le16(*(USHORT *)(&pMsg->KeyDesc.KeyInfo));
+
+ /* Fill in Key Length*/
+ if (bWPA2)
+ {
+ /* In WPA2 mode, the field indicates the length of pairwise key cipher, */
+ /* so only pairwise_msg_1 and pairwise_msg_3 need to fill. */
+ if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3))
+ pMsg->KeyDesc.KeyLength[1] = ((pEntry->WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_TK : LEN_AES_TK);
+ }
+ else if (!bWPA2)
+ {
+ if (MsgType >= EAPOL_GROUP_MSG_1)
+ {
+ /* the length of group key cipher*/
+ pMsg->KeyDesc.KeyLength[1] = ((GroupKeyWepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_GTK : LEN_AES_GTK);
+ }
+ else
+ {
+ /* the length of pairwise key cipher*/
+ pMsg->KeyDesc.KeyLength[1] = ((pEntry->WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_TK : LEN_AES_TK);
+ }
+ }
+
+ /* Fill in replay counter */
+ NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY);
+
+ /* Fill Key Nonce field */
+ /* ANonce : pairwise_msg1 & pairwise_msg3*/
+ /* SNonce : pairwise_msg2*/
+ /* GNonce : group_msg1_wpa1 */
+ if ((MsgType <= EAPOL_PAIR_MSG_3) || ((!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1))))
+ NdisMoveMemory(pMsg->KeyDesc.KeyNonce, KeyNonce, LEN_KEY_DESC_NONCE);
+
+ /* Fill key IV - WPA2 as 0, WPA1 as random*/
+ if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1))
+ {
+ /* Suggest IV be random number plus some number,*/
+ NdisMoveMemory(pMsg->KeyDesc.KeyIv, &KeyNonce[16], LEN_KEY_DESC_IV);
+ pMsg->KeyDesc.KeyIv[15] += 2;
+ }
+
+ /* Fill Key RSC field */
+ /* It contains the RSC for the GTK being installed.*/
+ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1))
+ {
+ NdisMoveMemory(pMsg->KeyDesc.KeyRsc, TxRSC, 6);
+ }
+
+ /* Clear Key MIC field for MIC calculation later */
+ NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+
+ ConstructEapolKeyData(pEntry,
+ GroupKeyWepStatus,
+ KeyDescVer,
+ MsgType,
+ DefaultKeyIdx,
+ GTK,
+ RSNIE,
+ RSNIE_Len,
+ pMsg);
+
+ /* Calculate MIC and fill in KeyMic Field except Pairwise Msg 1.*/
+ if (MsgType != EAPOL_PAIR_MSG_1)
+ {
+ CalculateMIC(KeyDescVer, pEntry->PTK, pMsg);
+ }
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===> ConstructEapolMsg for %s %s\n", ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType)));
+ DBGPRINT(RT_DEBUG_TRACE, (" Body length = %d \n", CONV_ARRARY_TO_UINT16(pMsg->Body_Len)));
+ DBGPRINT(RT_DEBUG_TRACE, (" Key length = %d \n", CONV_ARRARY_TO_UINT16(pMsg->KeyDesc.KeyLength)));
+
+
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Construct the Key Data field of EAPoL message
+
+ Arguments:
+ pAd Pointer to our adapter
+ Elem Message body
+
+ Return Value:
+ None
+
+ Note:
+
+ ========================================================================
+*/
+VOID ConstructEapolKeyData(
+ IN PMAC_TABLE_ENTRY pEntry,
+ IN UCHAR GroupKeyWepStatus,
+ IN UCHAR keyDescVer,
+ IN UCHAR MsgType,
+ IN UCHAR DefaultKeyIdx,
+ IN UCHAR *GTK,
+ IN UCHAR *RSNIE,
+ IN UCHAR RSNIE_LEN,
+ OUT PEAPOL_PACKET pMsg)
+{
+ UCHAR *mpool, *Key_Data, *eGTK;
+ ULONG data_offset;
+ BOOLEAN bWPA2Capable = FALSE;
+ BOOLEAN GTK_Included = FALSE;
+
+ /* Choose WPA2 or not*/
+ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) ||
+ (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
+ bWPA2Capable = TRUE;
+
+ if (MsgType == EAPOL_PAIR_MSG_1 ||
+ MsgType == EAPOL_PAIR_MSG_4 ||
+ MsgType == EAPOL_GROUP_MSG_2)
+ return;
+
+ /* allocate memory pool*/
+ os_alloc_mem(NULL, (PUCHAR *)&mpool, 1500);
+
+ if (mpool == NULL)
+ return;
+
+ /* eGTK Len = 512 */
+ eGTK = (UCHAR *) ROUND_UP(mpool, 4);
+ /* Key_Data Len = 512 */
+ Key_Data = (UCHAR *) ROUND_UP(eGTK + 512, 4);
+
+ NdisZeroMemory(Key_Data, 512);
+ SET_UINT16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, 0);
+ data_offset = 0;
+
+ /* Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3 */
+ if (RSNIE_LEN && ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3)))
+ {
+ PUINT8 pmkid_ptr = NULL;
+ UINT8 pmkid_len = 0;
+
+
+ RTMPInsertRSNIE(&Key_Data[data_offset],
+ &data_offset,
+ RSNIE,
+ RSNIE_LEN,
+ pmkid_ptr,
+ pmkid_len);
+ }
+
+
+ /* Encapsulate GTK */
+ /* Only for pairwise_msg3_WPA2 and group_msg1*/
+ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) || (MsgType == EAPOL_GROUP_MSG_1))
+ {
+ UINT8 gtk_len;
+
+ /* Decide the GTK length */
+ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)
+ gtk_len = LEN_AES_GTK;
+ else
+ gtk_len = LEN_TKIP_GTK;
+
+ /* Insert GTK KDE format in WAP2 mode */
+ if (bWPA2Capable)
+ {
+ /* Construct the common KDE format */
+ WPA_ConstructKdeHdr(KDE_GTK, 2 + gtk_len, &Key_Data[data_offset]);
+ data_offset += sizeof(KDE_HDR);
+
+ /* GTK KDE format - 802.11i-2004 Figure-43x*/
+ Key_Data[data_offset] = (DefaultKeyIdx & 0x03);
+ Key_Data[data_offset + 1] = 0x00; /* Reserved Byte*/
+ data_offset += 2;
+ }
+
+ /* Fill in GTK */
+ NdisMoveMemory(&Key_Data[data_offset], GTK, gtk_len);
+ data_offset += gtk_len;
+
+
+ GTK_Included = TRUE;
+ }
+
+
+
+ /* If the Encrypted Key Data subfield (of the Key Information field)
+ is set, the entire Key Data field shall be encrypted. */
+ /* This whole key-data field shall be encrypted if a GTK is included.*/
+ /* Encrypt the data material in key data field with KEK*/
+ if (GTK_Included)
+ {
+ /*hex_dump("GTK_Included", Key_Data, data_offset);*/
+
+ if (
+ (keyDescVer == KEY_DESC_AES))
+ {
+ UCHAR remainder = 0;
+ UCHAR pad_len = 0;
+ UINT wrap_len =0;
+
+ /* Key Descriptor Version 2 or 3: AES key wrap, defined in IETF RFC 3394, */
+ /* shall be used to encrypt the Key Data field using the KEK field from */
+ /* the derived PTK.*/
+
+ /* If the Key Data field uses the NIST AES key wrap, then the Key Data field */
+ /* shall be padded before encrypting if the key data length is less than 16 */
+ /* octets or if it is not a multiple of 8. The padding consists of appending*/
+ /* a single octet 0xdd followed by zero or more 0x00 octets. */
+ if ((remainder = data_offset & 0x07) != 0)
+ {
+ INT i;
+
+ pad_len = (8 - remainder);
+ Key_Data[data_offset] = 0xDD;
+ for (i = 1; i < pad_len; i++)
+ Key_Data[data_offset + i] = 0;
+
+ data_offset += pad_len;
+ }
+
+ AES_Key_Wrap(Key_Data, (UINT) data_offset,
+ &pEntry->PTK[LEN_PTK_KCK], LEN_PTK_KEK,
+ eGTK, &wrap_len);
+ data_offset = wrap_len;
+
+ }
+ else
+ {
+ TKIP_GTK_KEY_WRAP(&pEntry->PTK[LEN_PTK_KCK],
+ pMsg->KeyDesc.KeyIv,
+ Key_Data,
+ data_offset,
+ eGTK);
+ }
+
+ NdisMoveMemory(pMsg->KeyDesc.KeyData, eGTK, data_offset);
+ }
+ else
+ {
+ NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset);
+ }
+
+ /* Update key data length field and total body length*/
+ SET_UINT16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, data_offset);
+ INC_UINT16_TO_ARRARY(pMsg->Body_Len, data_offset);
+
+ os_free_mem(NULL, mpool);
+
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Calcaulate MIC. It is used during 4-ways handsharking.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ PeerWepStatus - indicate the encryption type
+
+ Return Value:
+
+ Note:
+ The EAPOL-Key MIC is a MIC of the EAPOL-Key frames,
+ from and including the EAPOL protocol version field
+ to and including the Key Data field, calculated with
+ the Key MIC field set to 0.
+
+ ========================================================================
+*/
+VOID CalculateMIC(
+ IN UCHAR KeyDescVer,
+ IN UCHAR *PTK,
+ OUT PEAPOL_PACKET pMsg)
+{
+ UCHAR *OutBuffer;
+ ULONG FrameLen = 0;
+ UCHAR mic[LEN_KEY_DESC_MIC];
+ UCHAR digest[80];
+
+ /* allocate memory for MIC calculation*/
+ os_alloc_mem(NULL, (PUCHAR *)&OutBuffer, 512);
+
+ if (OutBuffer == NULL)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("!!!CalculateMIC: no memory!!!\n"));
+ return;
+ }
+
+ /* make a frame for calculating MIC.*/
+ MakeOutgoingFrame(OutBuffer, &FrameLen,
+ CONV_ARRARY_TO_UINT16(pMsg->Body_Len) + 4, pMsg,
+ END_OF_ARGS);
+
+ NdisZeroMemory(mic, sizeof(mic));
+
+ /* Calculate MIC*/
+ if (KeyDescVer == KEY_DESC_AES)
+ {
+ RT_HMAC_SHA1(PTK, LEN_PTK_KCK, OutBuffer, FrameLen, digest, SHA1_DIGEST_SIZE);
+ NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC);
+ }
+ else if (KeyDescVer == KEY_DESC_TKIP)
+ {
+ RT_HMAC_MD5(PTK, LEN_PTK_KCK, OutBuffer, FrameLen, mic, MD5_DIGEST_SIZE);
+ }
+ else if (KeyDescVer == KEY_DESC_EXT)
+ {
+ UINT mlen = AES_KEY128_LENGTH;
+ AES_CMAC(OutBuffer, FrameLen, PTK, LEN_PTK_KCK, mic, &mlen);
+ }
+
+ /* store the calculated MIC*/
+ NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC);
+
+ os_free_mem(NULL, OutBuffer);
+}
+
+UCHAR RTMPExtractKeyIdxFromIVHdr(
+ IN PUCHAR pIV,
+ IN UINT8 CipherAlg)
+{
+ UCHAR keyIdx = 0xFF;
+
+ /* extract the key index from IV header */
+ switch (CipherAlg)
+ {
+ case Ndis802_11Encryption1Enabled:
+ case Ndis802_11Encryption2Enabled:
+ case Ndis802_11Encryption3Enabled:
+ keyIdx = (*(pIV + 3) & 0xc0) >> 6;
+ break;
+
+#ifdef WAPI_SUPPORT
+ case Ndis802_11EncryptionSMS4Enabled:
+ keyIdx = *(pIV) & 0xFF;
+ break;
+#endif /* WAPI_SUPPORT */
+ }
+
+ return keyIdx;
+
+}
+
+PCIPHER_KEY RTMPSwCipherKeySelection(
+ IN RTMP_ADAPTER *pAd,
+ IN PUCHAR pIV,
+ IN RX_BLK *pRxBlk,
+ IN MAC_TABLE_ENTRY *pEntry)
+{
+ PCIPHER_KEY pKey = NULL;
+ UCHAR keyIdx = 0;
+ UINT8 CipherAlg = Ndis802_11EncryptionDisabled;
+
+ if ((pEntry == NULL) ||
+ (RX_BLK_TEST_FLAG(pRxBlk, fRX_APCLI)) ||
+ (RX_BLK_TEST_FLAG(pRxBlk, fRX_WDS)) ||
+ (RX_BLK_TEST_FLAG(pRxBlk, fRX_MESH)))
+ return NULL;
+
+ if (pRxBlk->pRxInfo->U2M)
+ {
+ CipherAlg = pEntry->WepStatus;
+ }
+ else
+ {
+ }
+
+
+ if ((keyIdx = RTMPExtractKeyIdxFromIVHdr(pIV, CipherAlg)) > 3)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Invalid key index(%d) !!!\n",
+ __FUNCTION__, keyIdx));
+ return NULL;
+ }
+
+ if (CipherAlg == Ndis802_11Encryption1Enabled)
+ {
+ pKey = &pAd->SharedKey[pEntry->apidx][keyIdx];
+ }
+ else if ((CipherAlg == Ndis802_11Encryption2Enabled) ||
+ (CipherAlg == Ndis802_11Encryption3Enabled))
+ {
+ if (pRxBlk->pRxInfo->U2M)
+ pKey = &pEntry->PairwiseKey;
+ else {
+ pKey = &pAd->SharedKey[pEntry->apidx][keyIdx];
+ }
+ }
+#ifdef WAPI_SUPPORT
+ else if (CipherAlg == Ndis802_11EncryptionSMS4Enabled)
+ {
+ if (pRxBlk->pRxInfo->U2M)
+ pKey = &pEntry->PairwiseKey;
+ else
+ pKey = &pAd->SharedKey[pEntry->apidx][keyIdx];
+ }
+#endif /* WAPI_SUPPORT */
+
+ return pKey;
+
+}
+
+/*
+ ========================================================================
+
+ Routine Description:
+ Some received frames can't decrypt by Asic, so decrypt them by software.
+
+ Arguments:
+ pAd - pointer to our pAdapter context
+ PeerWepStatus - indicate the encryption type
+
+ Return Value:
+ NDIS_STATUS_SUCCESS - decryption successful
+ NDIS_STATUS_FAILURE - decryption failure
+
+ ========================================================================
+*/
+NDIS_STATUS RTMPSoftDecryptionAction(
+ IN PRTMP_ADAPTER pAd,
+ IN PUCHAR pHdr,
+ IN UCHAR UserPriority,
+ IN PCIPHER_KEY pKey,
+ INOUT PUCHAR pData,
+ INOUT UINT16 *DataByteCnt)
+{
+ switch (pKey->CipherAlg)
+ {
+ case CIPHER_WEP64:
+ case CIPHER_WEP128:
+ /* handle WEP decryption */
+ if (RTMPSoftDecryptWEP(pAd, pKey, pData, &(*DataByteCnt)) == FALSE)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : SW decrypt WEP data fails.\n"));
+ /* give up this frame*/
+ return NDIS_STATUS_FAILURE;
+ }
+ break;
+
+ case CIPHER_TKIP:
+ /* handle TKIP decryption */
+ if (RTMPSoftDecryptTKIP(pAd, pHdr, UserPriority,
+ pKey, pData, &(*DataByteCnt)) == FALSE)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : SW decrypt TKIP data fails.\n"));
+ /* give up this frame*/
+ return NDIS_STATUS_FAILURE;
+ }
+ break;
+
+ case CIPHER_AES:
+ /* handle AES decryption */
+ if (RTMPSoftDecryptCCMP(pAd, pHdr, pKey, pData, &(*DataByteCnt)) == FALSE)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : SW decrypt AES data fails.\n"));
+ /* give up this frame*/
+ return NDIS_STATUS_FAILURE;
+ }
+ break;
+#ifdef WAPI_SUPPORT
+#ifdef SOFT_ENCRYPT
+ case CIPHER_SMS4:
+ {
+ INT ret;
+#ifdef RT_BIG_ENDIAN
+ RTMPFrameEndianChange(pAd, pHdr, DIR_READ, FALSE);
+#endif
+ if ((ret = RTMPSoftDecryptSMS4(pHdr, FALSE, pKey, pData, &(*DataByteCnt))) != STATUS_SUCCESS)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : SW decrypt SMS4 data fails(%d).\n", ret));
+ /* give up this frame*/
+ return NDIS_STATUS_FAILURE;
+ }
+#ifdef RT_BIG_ENDIAN
+ RTMPFrameEndianChange(pAd, pHdr, DIR_READ, FALSE);
+#endif
+ }
+ break;
+#endif /* SOFT_ENCRYPT */
+#endif /* WAPI_SUPPORT */
+ default:
+ /* give up this frame*/
+ return NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+VOID RTMPSoftConstructIVHdr(
+ IN UCHAR CipherAlg,
+ IN UCHAR key_id,
+ IN PUCHAR pTxIv,
+ OUT PUCHAR pHdrIv,
+ OUT UINT8 *hdr_iv_len)
+{
+ *hdr_iv_len = 0;
+
+#ifdef WAPI_SUPPORT
+ if (CipherAlg == CIPHER_SMS4)
+ {
+ /* Construct and insert WPI-SMS4 IV header to MPDU header */
+ RTMPConstructWPIIVHdr(key_id, pTxIv, pHdrIv);
+ *hdr_iv_len = LEN_WPI_IV_HDR;
+ }
+ else
+#endif /* WAPI_SUPPORT */
+ if ((CipherAlg == CIPHER_WEP64) || (CipherAlg == CIPHER_WEP128))
+ {
+ /* Construct and insert 4-bytes WEP IV header to MPDU header */
+ RTMPConstructWEPIVHdr(key_id, pTxIv, pHdrIv);
+ *hdr_iv_len = LEN_WEP_IV_HDR;
+ }
+ else if (CipherAlg == CIPHER_TKIP)
+ ;
+ else if (CipherAlg == CIPHER_AES)
+ {
+ /* Construct and insert 8-bytes CCMP header to MPDU header */
+ RTMPConstructCCMPHdr(key_id, pTxIv, pHdrIv);
+ *hdr_iv_len = LEN_CCMP_HDR;
+ }
+
+}
+
+VOID RTMPSoftEncryptionAction(
+ IN PRTMP_ADAPTER pAd,
+ IN UCHAR CipherAlg,
+ IN PUCHAR pHdr,
+ IN PUCHAR pSrcBufData,
+ IN UINT32 SrcBufLen,
+ IN UCHAR KeyIdx,
+ IN PCIPHER_KEY pKey,
+ OUT UINT8 *ext_len)
+{
+ *ext_len = 0;
+
+#ifdef WAPI_SUPPORT
+#ifdef SOFT_ENCRYPT
+ if (CipherAlg == CIPHER_SMS4)
+ {
+#ifdef RT_BIG_ENDIAN
+ RTMPFrameEndianChange(pAd, pHdr, DIR_READ, FALSE);
+#endif
+ /* Encrypt the MPDU data by software*/
+ RTMPSoftEncryptSMS4(pHdr,
+ pSrcBufData,
+ SrcBufLen,
+ KeyIdx,
+ pKey->Key,
+ pKey->TxTsc);
+#ifdef RT_BIG_ENDIAN
+ RTMPFrameEndianChange(pAd, pHdr, DIR_READ, FALSE);
+#endif
+ *ext_len = LEN_WPI_MIC;
+ }
+ else
+#endif /* SOFT_ENCRYPT */
+#endif /* WAPI_SUPPORT */
+ if ((CipherAlg == CIPHER_WEP64) || (CipherAlg == CIPHER_WEP128))
+ {
+ /* Encrypt the MPDU data by software*/
+ RTMPSoftEncryptWEP(pAd,
+ pKey->TxTsc,
+ pKey,
+ pSrcBufData,
+ SrcBufLen);
+
+ *ext_len = LEN_ICV;
+ }
+ else if (CipherAlg == CIPHER_TKIP)
+ ;
+ else if (CipherAlg == CIPHER_AES)
+ {
+ /* Encrypt the MPDU data by software*/
+ RTMPSoftEncryptCCMP(pAd,
+ pHdr,
+ pKey->TxTsc,
+ pKey->Key,
+ pSrcBufData,
+ SrcBufLen);
+
+ *ext_len = LEN_CCMP_MIC;
+ }
+
+}
+
+PUINT8 WPA_ExtractSuiteFromRSNIE(
+ IN PUINT8 rsnie,
+ IN UINT rsnie_len,
+ IN UINT8 type,
+ OUT UINT8 *count)
+{
+ PEID_STRUCT pEid;
+ INT len;
+ PUINT8 pBuf;
+ INT offset = 0;
+
+ pEid = (PEID_STRUCT)rsnie;
+ len = rsnie_len - 2; /* exclude IE and length*/
+ pBuf = (PUINT8)&pEid->Octet[0];
+
+ /* set default value*/
+ *count = 0;
+
+ /* Check length*/
+ if ((len <= 0) || (pEid->Len != len))
+ {
+ DBGPRINT_ERR(("%s : The length is invalid\n", __FUNCTION__));
+ goto out;
+ }
+
+ /* Check WPA or WPA2*/
+ if (pEid->Eid == IE_WPA)
+ {
+ /* Check the length */
+ if (len < sizeof(RSNIE))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The length is too short for WPA\n", __FUNCTION__));
+ goto out;
+ }
+ else
+ {
+ PRSNIE pRsnie;
+ UINT16 u_cnt;
+
+ pRsnie = (PRSNIE)pBuf;
+ u_cnt = cpu2le16(pRsnie->ucount);
+ offset = sizeof(RSNIE) + (LEN_OUI_SUITE * (u_cnt - 1));
+
+ if (len < offset)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The expected lenght(%d) exceed the remaining length(%d) for WPA-RSN \n",
+ __FUNCTION__, offset, len));
+ goto out;
+ }
+ else
+ {
+ /* Get the group cipher*/
+ if (type == GROUP_SUITE)
+ {
+ *count = 1;
+ return pRsnie->mcast;
+ }
+ /* Get the pairwise cipher suite*/
+ else if (type == PAIRWISE_SUITE)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("%s : The count of pairwise cipher is %d\n",
+ __FUNCTION__, u_cnt));
+ *count = u_cnt;
+ return pRsnie->ucast[0].oui;
+ }
+ }
+ }
+ }
+ else if (pEid->Eid == IE_RSN)
+ {
+ if (len < sizeof(RSNIE2))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The length is too short for WPA2\n", __FUNCTION__));
+ goto out;
+ }
+ else
+ {
+ PRSNIE2 pRsnie2;
+ UINT16 u_cnt;
+
+ pRsnie2 = (PRSNIE2)pBuf;
+ u_cnt = cpu2le16(pRsnie2->ucount);
+ offset = sizeof(RSNIE2) + (LEN_OUI_SUITE * (u_cnt - 1));
+
+ if (len < offset)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The expected lenght(%d) exceed the remaining length(%d) for WPA2-RSN \n",
+ __FUNCTION__, offset, len));
+ goto out;
+ }
+ else
+ {
+ /* Get the group cipher*/
+ if (type == GROUP_SUITE)
+ {
+ *count = 1;
+ return pRsnie2->mcast;
+ }
+ /* Get the pairwise cipher suite*/
+ else if (type == PAIRWISE_SUITE)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("%s : The count of pairwise cipher is %d\n",
+ __FUNCTION__, u_cnt));
+ *count = u_cnt;
+ return pRsnie2->ucast[0].oui;
+ }
+ }
+ }
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Unknown IE (%d)\n", __FUNCTION__, pEid->Eid));
+ goto out;
+ }
+
+ /* skip group cipher and pairwise cipher suite */
+ pBuf += offset;
+ len -= offset;
+
+ /* Ready to extract the AKM information and its count */
+ if (len < sizeof(RSNIE_AUTH))
+ {
+ DBGPRINT_ERR(("%s : The length of AKM of RSN is too short\n", __FUNCTION__));
+ goto out;
+ }
+ else
+ {
+ PRSNIE_AUTH pAkm;
+ UINT16 a_cnt;
+
+ /* pointer to AKM count */
+ pAkm = (PRSNIE_AUTH)pBuf;
+ a_cnt = cpu2le16(pAkm->acount);
+ offset = sizeof(RSNIE_AUTH) + (LEN_OUI_SUITE * (a_cnt - 1));
+
+ if (len < offset)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The expected lenght(%d) exceed the remaining length(%d) for AKM \n",
+ __FUNCTION__, offset, len));
+ goto out;
+ }
+ else
+ {
+ /* Get the AKM suite */
+ if (type == AKM_SUITE)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("%s : The count of AKM is %d\n",
+ __FUNCTION__, a_cnt));
+ *count = a_cnt;
+ return pAkm->auth[0].oui;
+ }
+ }
+ }
+
+ /* For WPA1, the remaining shall be ignored. */
+ if (pEid->Eid == IE_WPA)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("%s : The remaining shall be ignored in WPA mode\n",
+ __FUNCTION__));
+ goto out;
+ }
+
+ /* skip the AKM capability */
+ pBuf += offset;
+ len -= offset;
+
+ /* Parse the RSN Capabilities */
+ if (len < sizeof(RSN_CAPABILITIES))
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("%s : The peer RSNIE doesn't include RSN-Cap\n", __FUNCTION__));
+ goto out;
+ }
+ else
+ {
+ /* Report the content of the RSN capabilities */
+ if (type == RSN_CAP_INFO)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("%s : Extract RSN Capabilities\n", __FUNCTION__));
+ *count = 1;
+ return pBuf;
+ }
+
+ /* skip RSN capability (2-bytes) */
+ offset = sizeof(RSN_CAPABILITIES);
+ pBuf += offset;
+ len -= offset;
+ }
+
+ /* Extract PMKID-list field */
+ if (len < sizeof(UINT16))
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("%s : The peer RSNIE doesn't include PMKID list Count\n", __FUNCTION__));
+ goto out;
+ }
+ else
+ {
+ UINT16 p_count;
+ PUINT8 pPmkidList = NULL;
+
+ NdisMoveMemory(&p_count, pBuf, sizeof(UINT16));
+ p_count = cpu2le16(p_count);
+
+ /* Get count of the PMKID list */
+ if (p_count > 0)
+ {
+ PRSNIE_PMKID pRsnPmkid;
+
+ /* the expected length of PMKID-List field */
+ offset = sizeof(RSNIE_PMKID) + (LEN_PMKID * (p_count - 1));
+
+ /* sanity check about the length of PMKID-List field */
+ if (len < offset)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The expected lenght(%d) exceed the remaining length(%d) in PMKID-field \n",
+ __FUNCTION__, offset, len));
+ goto out;
+ }
+
+ /* pointer to PMKID field */
+ pRsnPmkid = (PRSNIE_PMKID)pBuf;
+ pPmkidList = pRsnPmkid->pmkid[0].list;
+
+ }
+ else
+ {
+ /* The PMKID field shall be without PMKID-List */
+ offset = sizeof(UINT16);
+ pPmkidList = NULL;
+ }
+
+
+ /* Extract PMKID list and its count */
+ if (type == PMKID_LIST)
+ {
+ *count = p_count;
+ return pPmkidList;
+ }
+
+ /* skip the PMKID field */
+ pBuf += offset;
+ len -= offset;
+
+ }
+
+
+out:
+ *count = 0;
+ return NULL;
+
+}
+
+VOID WpaShowAllsuite(
+ IN PUINT8 rsnie,
+ IN UINT rsnie_len)
+{
+ PUINT8 pSuite = NULL;
+ UINT8 count;
+
+ hex_dump("RSNIE", rsnie, rsnie_len);
+
+ /* group cipher*/
+ if ((pSuite = WPA_ExtractSuiteFromRSNIE(rsnie, rsnie_len, GROUP_SUITE, &count)) != NULL)
+ {
+ hex_dump("group cipher", pSuite, 4*count);
+ }
+
+ /* pairwise cipher*/
+ if ((pSuite = WPA_ExtractSuiteFromRSNIE(rsnie, rsnie_len, PAIRWISE_SUITE, &count)) != NULL)
+ {
+ hex_dump("pairwise cipher", pSuite, 4*count);
+ }
+
+ /* AKM*/
+ if ((pSuite = WPA_ExtractSuiteFromRSNIE(rsnie, rsnie_len, AKM_SUITE, &count)) != NULL)
+ {
+ hex_dump("AKM suite", pSuite, 4*count);
+ }
+
+ /* PMKID*/
+ if ((pSuite = WPA_ExtractSuiteFromRSNIE(rsnie, rsnie_len, PMKID_LIST, &count)) != NULL)
+ {
+ hex_dump("PMKID", pSuite, LEN_PMKID);
+ }
+
+}
+
+VOID RTMPInsertRSNIE(
+ IN PUCHAR pFrameBuf,
+ OUT PULONG pFrameLen,
+ IN PUINT8 rsnie_ptr,
+ IN UINT8 rsnie_len,
+ IN PUINT8 pmkid_ptr,
+ IN UINT8 pmkid_len)
+{
+ PUCHAR pTmpBuf;
+ ULONG TempLen = 0;
+ UINT8 extra_len = 0;
+ UINT16 pmk_count = 0;
+ UCHAR ie_num;
+ UINT8 total_len = 0;
+ UCHAR WPA2_OUI[3]={0x00,0x0F,0xAC};
+
+ pTmpBuf = pFrameBuf;
+
+ /* PMKID-List Must larger than 0 and the multiple of 16. */
+ if (pmkid_len > 0 && ((pmkid_len & 0x0f) == 0))
+ {
+ extra_len = sizeof(UINT16) + pmkid_len;
+
+ pmk_count = (pmkid_len >> 4);
+ pmk_count = cpu2le16(pmk_count);
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("%s : no PMKID-List included(%d).\n", __FUNCTION__, pmkid_len));
+ }
+
+ if (rsnie_len != 0)
+ {
+ ie_num = IE_WPA;
+ total_len = rsnie_len;
+
+ if (NdisEqualMemory(rsnie_ptr + 2, WPA2_OUI, sizeof(WPA2_OUI)))
+ {
+ ie_num = IE_RSN;
+ total_len += extra_len;
+ }
+
+ /* construct RSNIE body */
+ MakeOutgoingFrame(pTmpBuf, &TempLen,
+ 1, &ie_num,
+ 1, &total_len,
+ rsnie_len, rsnie_ptr,
+ END_OF_ARGS);
+
+ pTmpBuf += TempLen;
+ *pFrameLen = *pFrameLen + TempLen;
+
+ if (ie_num == IE_RSN)
+ {
+ /* Insert PMKID-List field */
+ if (extra_len > 0)
+ {
+ MakeOutgoingFrame(pTmpBuf, &TempLen,
+ 2, &pmk_count,
+ pmkid_len, pmkid_ptr,
+ END_OF_ARGS);
+
+ pTmpBuf += TempLen;
+ *pFrameLen = *pFrameLen + TempLen;
+ }
+ }
+ }
+
+ return;
+}
+
+
+VOID WPAInstallPairwiseKey(
+ PRTMP_ADAPTER pAd,
+ UINT8 BssIdx,
+ PMAC_TABLE_ENTRY pEntry,
+ BOOLEAN bAE)
+{
+ NdisZeroMemory(&pEntry->PairwiseKey, sizeof(CIPHER_KEY));
+
+ /* Assign the pairwise cipher algorithm */
+ if (pEntry->WepStatus == Ndis802_11Encryption2Enabled)
+ pEntry->PairwiseKey.CipherAlg = CIPHER_TKIP;
+ else if (pEntry->WepStatus == Ndis802_11Encryption3Enabled)
+ pEntry->PairwiseKey.CipherAlg = CIPHER_AES;
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : fails (wcid-%d)\n",
+ __FUNCTION__, pEntry->Aid));
+ return;
+ }
+
+ /* Assign key material and its length */
+ pEntry->PairwiseKey.KeyLen = LEN_TK;
+ NdisMoveMemory(pEntry->PairwiseKey.Key, &pEntry->PTK[OFFSET_OF_PTK_TK], LEN_TK);
+ if (pEntry->PairwiseKey.CipherAlg == CIPHER_TKIP)
+ {
+ if (bAE)
+ {
+ NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pEntry->PTK[OFFSET_OF_AP_TKIP_TX_MIC], LEN_TKIP_MIC);
+ NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pEntry->PTK[OFFSET_OF_AP_TKIP_RX_MIC], LEN_TKIP_MIC);
+ }
+ else
+ {
+ NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pEntry->PTK[OFFSET_OF_STA_TKIP_TX_MIC], LEN_TKIP_MIC);
+ NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pEntry->PTK[OFFSET_OF_STA_TKIP_RX_MIC], LEN_TKIP_MIC);
+ }
+ }
+
+#ifdef SOFT_ENCRYPT
+ if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SOFTWARE_ENCRYPT))
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("===> SW_ENC ON(wcid=%d) \n", pEntry->Aid));
+ NdisZeroMemory(pEntry->PairwiseKey.TxTsc, LEN_WPA_TSC);
+ NdisZeroMemory(pEntry->PairwiseKey.RxTsc, LEN_WPA_TSC);
+ }
+ else
+#endif /* SOFT_ENCRYPT */
+ {
+ /* Add Pair-wise key to Asic */
+ AsicAddPairwiseKeyEntry(
+ pAd,
+ (UCHAR)pEntry->Aid,
+ &pEntry->PairwiseKey);
+
+ RTMPSetWcidSecurityInfo(pAd,
+ BssIdx,
+ 0,
+ pEntry->PairwiseKey.CipherAlg,
+ (UCHAR)pEntry->Aid,
+ PAIRWISEKEYTABLE);
+ }
+
+}
+
+VOID WPAInstallSharedKey(
+ PRTMP_ADAPTER pAd,
+ UINT8 GroupCipher,
+ UINT8 BssIdx,
+ UINT8 KeyIdx,
+ UINT8 Wcid,
+ BOOLEAN bAE,
+ PUINT8 pGtk,
+ UINT8 GtkLen)
+{
+ PCIPHER_KEY pSharedKey;
+
+ if (BssIdx >= MAX_MBSSID_NUM(pAd))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The BSS-index(%d) is out of range for MBSSID link. \n",
+ __FUNCTION__, BssIdx));
+ return;
+ }
+
+ pSharedKey = &pAd->SharedKey[BssIdx][KeyIdx];
+ NdisZeroMemory(pSharedKey, sizeof(CIPHER_KEY));
+
+ /* Set the group cipher */
+ if (GroupCipher == Ndis802_11GroupWEP40Enabled)
+ pSharedKey->CipherAlg = CIPHER_WEP64;
+ else if (GroupCipher == Ndis802_11GroupWEP104Enabled)
+ pSharedKey->CipherAlg = CIPHER_WEP128;
+ else if (GroupCipher == Ndis802_11Encryption2Enabled)
+ pSharedKey->CipherAlg = CIPHER_TKIP;
+ else if (GroupCipher == Ndis802_11Encryption3Enabled)
+ pSharedKey->CipherAlg = CIPHER_AES;
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : fails (IF/ra%d) \n",
+ __FUNCTION__, BssIdx));
+ return;
+ }
+
+ /* Set the key material and its length */
+ if (GroupCipher == Ndis802_11GroupWEP40Enabled ||
+ GroupCipher == Ndis802_11GroupWEP104Enabled)
+ {
+ /* Sanity check the length */
+ if ((GtkLen != LEN_WEP64) && (GtkLen != LEN_WEP128))
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : (IF/ra%d) WEP key invlaid(%d) \n",
+ __FUNCTION__, BssIdx, GtkLen));
+ return;
+ }
+
+ pSharedKey->KeyLen = GtkLen;
+ NdisMoveMemory(pSharedKey->Key, pGtk, GtkLen);
+ }
+ else
+ {
+ /* Sanity check the length */
+ if (GtkLen < LEN_TK)
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : (IF/ra%d) WPA key invlaid(%d) \n",
+ __FUNCTION__, BssIdx, GtkLen));
+ return;
+ }
+
+ pSharedKey->KeyLen = LEN_TK;
+ NdisMoveMemory(pSharedKey->Key, pGtk, LEN_TK);
+ if (pSharedKey->CipherAlg == CIPHER_TKIP)
+ {
+ if (bAE)
+ {
+ NdisMoveMemory(pSharedKey->TxMic, pGtk + 16, LEN_TKIP_MIC);
+ NdisMoveMemory(pSharedKey->RxMic, pGtk + 24, LEN_TKIP_MIC);
+ }
+ else
+ {
+ NdisMoveMemory(pSharedKey->TxMic, pGtk + 24, LEN_TKIP_MIC);
+ NdisMoveMemory(pSharedKey->RxMic, pGtk + 16, LEN_TKIP_MIC);
+ }
+ }
+ }
+
+ /* Update group key table(0x6C00) and group key mode(0x7000) */
+ AsicAddSharedKeyEntry(
+ pAd,
+ BssIdx,
+ KeyIdx,
+ pSharedKey);
+
+ /* When Wcid isn't zero, it means that this is a Authenticator Role.
+ Only Authenticator entity needs to set HW IE/EIV table (0x6000)
+ and WCID attribute table (0x6800) for group key. */
+ if (Wcid != 0)
+ {
+ RTMPSetWcidSecurityInfo(pAd,
+ BssIdx,
+ KeyIdx,
+ pSharedKey->CipherAlg,
+ Wcid,
+ SHAREDKEYTABLE);
+ }
+}
+
+VOID RTMPSetWcidSecurityInfo(
+ PRTMP_ADAPTER pAd,
+ UINT8 BssIdx,
+ UINT8 KeyIdx,
+ UINT8 CipherAlg,
+ UINT8 Wcid,
+ UINT8 KeyTabFlag)
+{
+ UINT32 IV = 0;
+ UINT8 IV_KEYID = 0;
+
+ /* Prepare initial IV value */
+ if (CipherAlg == CIPHER_WEP64 || CipherAlg == CIPHER_WEP128)
+ {
+ INT i;
+ UCHAR TxTsc[LEN_WEP_TSC];
+
+ /* Generate 3-bytes IV randomly for encryption using */
+ for(i = 0; i < LEN_WEP_TSC; i++)
+ TxTsc[i] = RandomByte(pAd);
+
+ /* Update HW IVEIV table */
+ IV_KEYID = (KeyIdx << 6);
+ IV = (IV_KEYID << 24) |
+ (TxTsc[2] << 16) |
+ (TxTsc[1] << 8) |
+ (TxTsc[0]);
+ }
+ else if (CipherAlg == CIPHER_TKIP || CipherAlg == CIPHER_AES)
+ {
+ /* Set IVEIV as 1 in Asic -
+ In IEEE 802.11-2007 8.3.3.4.3 described :
+ The PN shall be implemented as a 48-bit monotonically incrementing
+ non-negative integer, initialized to 1 when the corresponding
+ temporal key is initialized or refreshed. */
+ IV_KEYID = (KeyIdx << 6) | 0x20;
+ IV = (IV_KEYID << 24) | 1;
+ }
+ else
+ {
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Unsupport cipher Alg (%d) for Wcid-%d \n",
+ __FUNCTION__, CipherAlg, Wcid));
+ return;
+ }
+ /* Update WCID IV/EIV table */
+ AsicUpdateWCIDIVEIV(pAd, Wcid, IV, 0);
+
+ /* Update WCID attribute entry */
+ AsicUpdateWcidAttributeEntry(pAd,
+ BssIdx,
+ KeyIdx,
+ CipherAlg,
+ Wcid,
+ KeyTabFlag);
+
+}
+