]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/staging/rt3070/sta/wpa.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / staging / rt3070 / sta / wpa.c
diff --git a/drivers/staging/rt3070/sta/wpa.c b/drivers/staging/rt3070/sta/wpa.c
new file mode 100644 (file)
index 0000000..63d0830
--- /dev/null
@@ -0,0 +1,2099 @@
+/*
+ *************************************************************************
+ * Ralink Tech Inc.
+ * 5F., No.36, Taiyuan St., Jhubei City,
+ * Hsinchu County 302,
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2007, Ralink Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify  *
+ * it under the terms of the GNU General Public License as published by  *
+ * the Free Software Foundation; either version 2 of the License, or     *
+ * (at your option) any later version.                                   *
+ *                                                                       *
+ * This program is distributed in the hope that it will be useful,       *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ * GNU General Public License for more details.                          *
+ *                                                                       *
+ * You should have received a copy of the GNU General Public License     *
+ * along with this program; if not, write to the                         *
+ * Free Software Foundation, Inc.,                                       *
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *                                                                       *
+ *************************************************************************
+
+       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"
+
+#define                WPARSNIE        0xdd
+#define                WPA2RSNIE       0x30
+
+//extern UCHAR BIT8[];
+UCHAR  CipherWpaPskTkip[] = {
+               0xDD, 0x16,                             // RSN IE
+               0x00, 0x50, 0xf2, 0x01, // oui
+               0x01, 0x00,                             // Version
+               0x00, 0x50, 0xf2, 0x02, // Multicast
+               0x01, 0x00,                             // Number of unicast
+               0x00, 0x50, 0xf2, 0x02, // unicast
+               0x01, 0x00,                             // number of authentication method
+               0x00, 0x50, 0xf2, 0x02  // authentication
+               };
+UCHAR  CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR));
+
+UCHAR  CipherWpaPskAes[] = {
+               0xDD, 0x16,                     // RSN IE
+               0x00, 0x50, 0xf2, 0x01, // oui
+               0x01, 0x00,                             // Version
+               0x00, 0x50, 0xf2, 0x04, // Multicast
+               0x01, 0x00,                             // Number of unicast
+               0x00, 0x50, 0xf2, 0x04, // unicast
+               0x01, 0x00,                             // number of authentication method
+               0x00, 0x50, 0xf2, 0x02  // authentication
+               };
+UCHAR  CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR));
+
+UCHAR  CipherSuiteCiscoCCKM[] = {
+               0xDD, 0x16,                             // RSN IE
+               0x00, 0x50, 0xf2, 0x01, // oui
+               0x01, 0x00,                             // Version
+               0x00, 0x40, 0x96, 0x01, // Multicast
+               0x01, 0x00,                             // Number of uicast
+               0x00, 0x40, 0x96, 0x01, // unicast
+               0x01, 0x00,                             // number of authentication method
+               0x00, 0x40, 0x96, 0x00  // Authentication
+               };
+UCHAR  CipherSuiteCiscoCCKMLen = (sizeof(CipherSuiteCiscoCCKM) / sizeof(UCHAR));
+
+UCHAR  CipherSuiteCiscoCCKM24[] = {
+               0xDD, 0x18,                             // RSN IE
+               0x00, 0x50, 0xf2, 0x01, // oui
+               0x01, 0x00,                             // Version
+               0x00, 0x40, 0x96, 0x01, // Multicast
+               0x01, 0x00,                             // Number of uicast
+               0x00, 0x40, 0x96, 0x01, // unicast
+               0x01, 0x00,                             // number of authentication method
+               0x00, 0x40, 0x96, 0x00,
+               0x28, 0x00// Authentication
+               };
+
+UCHAR  CipherSuiteCiscoCCKM24Len = (sizeof(CipherSuiteCiscoCCKM24) / sizeof(UCHAR));
+
+UCHAR  CipherSuiteCCXTkip[] = {
+               0xDD, 0x16,                             // RSN IE
+               0x00, 0x50, 0xf2, 0x01, // oui
+               0x01, 0x00,                             // Version
+               0x00, 0x50, 0xf2, 0x02, // Multicast
+               0x01, 0x00,                             // Number of unicast
+               0x00, 0x50, 0xf2, 0x02, // unicast
+               0x01, 0x00,                             // number of authentication method
+               0x00, 0x50, 0xf2, 0x01  // authentication
+               };
+UCHAR  CipherSuiteCCXTkipLen = (sizeof(CipherSuiteCCXTkip) / sizeof(UCHAR));
+
+UCHAR  CCX_LLC_HDR[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02};
+UCHAR  LLC_NORMAL[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
+
+UCHAR  EAPOL_FRAME[] = {0x88, 0x8E};
+
+BOOLEAN CheckRSNIE(
+       IN  PRTMP_ADAPTER   pAd,
+       IN  PUCHAR          pData,
+       IN  UCHAR           DataLen,
+       OUT     UCHAR                   *Offset);
+
+void inc_byte_array(UCHAR *counter, int len);
+
+/*
+       ========================================================================
+
+       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.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;
+}
+
+/*
+       ==========================================================================
+       Description:
+               association     state machine init,     including state transition and timer init
+       Parameters:
+               S -     pointer to the association state machine
+       ==========================================================================
+ */
+VOID WpaPskStateMachineInit(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      STATE_MACHINE *S,
+       OUT     STATE_MACHINE_FUNC Trans[])
+{
+       StateMachineInit(S,     Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE);
+       StateMachineSetAction(S, WPA_PSK_IDLE, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction);
+}
+
+/*
+       ==========================================================================
+       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)
+
+{
+       INT             MsgType = EAPOL_MSG_INVALID;
+       PKEY_DESCRIPTER pKeyDesc;
+       PHEADER_802_11  pHeader; //red
+       UCHAR           ZeroReplay[LEN_KEY_DESC_REPLAY];
+       UCHAR EapolVr;
+       KEY_INFO                peerKeyInfo;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("-----> WpaEAPOLKeyAction\n"));
+
+       // Get 802.11 header first
+       pHeader = (PHEADER_802_11) Elem->Msg;
+
+       // Get EAPoL-Key Descriptor
+       pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)];
+
+       NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
+       NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pKeyDesc->KeyInfo, sizeof(KEY_INFO));
+
+       *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo));
+
+
+       // 1. Check EAPOL frame version and type
+       EapolVr = (UCHAR) Elem->Msg[LENGTH_802_11+LENGTH_802_1_H];
+
+    if (((EapolVr != EAPOL_VER) && (EapolVr != EAPOL_VER2)) || ((pKeyDesc->Type != WPA1_KEY_DESC) && (pKeyDesc->Type != WPA2_KEY_DESC)))
+       {
+        DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n"));
+                       return;
+       }
+
+       // First validate replay counter, only accept message with larger replay counter
+       // Let equal pass, some AP start with all zero replay counter
+       NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY);
+
+       if((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) &&
+               (RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("   ReplayCounter not match   \n"));
+               return;
+       }
+
+       // Process WPA2PSK frame
+       if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
+       {
+               if((peerKeyInfo.KeyType == PAIRWISEKEY) &&
+                       (peerKeyInfo.EKD_DL == 0) &&
+                       (peerKeyInfo.KeyAck == 1) &&
+                       (peerKeyInfo.KeyMic == 0) &&
+                       (peerKeyInfo.Secure == 0) &&
+                       (peerKeyInfo.Error == 0) &&
+                       (peerKeyInfo.Request == 0))
+               {
+                       MsgType = EAPOL_PAIR_MSG_1;
+                       DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n"));
+               } else if((peerKeyInfo.KeyType == PAIRWISEKEY) &&
+                       (peerKeyInfo.EKD_DL  == 1) &&
+                       (peerKeyInfo.KeyAck == 1) &&
+                       (peerKeyInfo.KeyMic == 1) &&
+                       (peerKeyInfo.Secure == 1) &&
+                       (peerKeyInfo.Error == 0) &&
+                       (peerKeyInfo.Request == 0))
+               {
+                       MsgType = EAPOL_PAIR_MSG_3;
+                       DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n"));
+               } else if((peerKeyInfo.KeyType == GROUPKEY) &&
+                       (peerKeyInfo.EKD_DL == 1) &&
+                       (peerKeyInfo.KeyAck == 1) &&
+                       (peerKeyInfo.KeyMic == 1) &&
+                       (peerKeyInfo.Secure == 1) &&
+                       (peerKeyInfo.Error == 0) &&
+                       (peerKeyInfo.Request == 0))
+               {
+                       MsgType = EAPOL_GROUP_MSG_1;
+                       DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n"));
+               }
+
+               // We will assume link is up (assoc suceess and port not secured).
+               // All state has to be able to process message from previous state
+               switch(pAd->StaCfg.WpaState)
+               {
+               case SS_START:
+                       if(MsgType == EAPOL_PAIR_MSG_1)
+                       {
+                               Wpa2PairMsg1Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
+                       }
+                       break;
+
+               case SS_WAIT_MSG_3:
+                       if(MsgType == EAPOL_PAIR_MSG_1)
+                       {
+                               Wpa2PairMsg1Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
+                       }
+                       else if(MsgType == EAPOL_PAIR_MSG_3)
+                       {
+                               Wpa2PairMsg3Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_GROUP;
+                       }
+                       break;
+
+               case SS_WAIT_GROUP:             // When doing group key exchange
+               case SS_FINISH:                 // This happened when update group key
+                       if(MsgType == EAPOL_PAIR_MSG_1)
+                       {
+                           // Reset port secured variable
+                               pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
+                               Wpa2PairMsg1Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
+                       }
+                       else if(MsgType == EAPOL_PAIR_MSG_3)
+                       {
+                           // Reset port secured variable
+                               pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
+                               Wpa2PairMsg3Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_GROUP;
+                       }
+                       else if(MsgType == EAPOL_GROUP_MSG_1)
+                       {
+                               WpaGroupMsg1Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_FINISH;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+       // Process WPAPSK Frame
+       // Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant
+       else if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)
+       {
+               if((peerKeyInfo.KeyType == PAIRWISEKEY) &&
+                       (peerKeyInfo.KeyIndex == 0) &&
+                       (peerKeyInfo.KeyAck == 1) &&
+                       (peerKeyInfo.KeyMic == 0) &&
+                       (peerKeyInfo.Secure == 0) &&
+                       (peerKeyInfo.Error == 0) &&
+                       (peerKeyInfo.Request == 0))
+               {
+                       MsgType = EAPOL_PAIR_MSG_1;
+                       DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n"));
+               }
+               else if((peerKeyInfo.KeyType == PAIRWISEKEY) &&
+                       (peerKeyInfo.KeyIndex == 0) &&
+                       (peerKeyInfo.KeyAck == 1) &&
+                       (peerKeyInfo.KeyMic == 1) &&
+                       (peerKeyInfo.Secure == 0) &&
+                       (peerKeyInfo.Error == 0) &&
+                       (peerKeyInfo.Request == 0))
+               {
+                       MsgType = EAPOL_PAIR_MSG_3;
+                       DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n"));
+               }
+               else if((peerKeyInfo.KeyType == GROUPKEY) &&
+                       (peerKeyInfo.KeyIndex != 0) &&
+                       (peerKeyInfo.KeyAck == 1) &&
+                       (peerKeyInfo.KeyMic == 1) &&
+                       (peerKeyInfo.Secure == 1) &&
+                       (peerKeyInfo.Error == 0) &&
+                       (peerKeyInfo.Request == 0))
+               {
+                       MsgType = EAPOL_GROUP_MSG_1;
+                       DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n"));
+               }
+
+               // We will assume link is up (assoc suceess and port not secured).
+               // All state has to be able to process message from previous state
+               switch(pAd->StaCfg.WpaState)
+               {
+               case SS_START:
+                       if(MsgType == EAPOL_PAIR_MSG_1)
+                       {
+                               WpaPairMsg1Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
+                       }
+                       break;
+
+               case SS_WAIT_MSG_3:
+                       if(MsgType == EAPOL_PAIR_MSG_1)
+                       {
+                               WpaPairMsg1Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
+                       }
+                       else if(MsgType == EAPOL_PAIR_MSG_3)
+                       {
+                               WpaPairMsg3Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_GROUP;
+                       }
+                       break;
+
+               case SS_WAIT_GROUP:             // When doing group key exchange
+               case SS_FINISH:                 // This happened when update group key
+                       if(MsgType == EAPOL_PAIR_MSG_1)
+                       {
+                               WpaPairMsg1Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
+                               // Reset port secured variable
+                               pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
+                       }
+                       else if(MsgType == EAPOL_PAIR_MSG_3)
+                       {
+                               WpaPairMsg3Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_WAIT_GROUP;
+                               // Reset port secured variable
+                               pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
+                       }
+                       else if(MsgType == EAPOL_GROUP_MSG_1)
+                       {
+                               WpaGroupMsg1Action(pAd, Elem);
+                               pAd->StaCfg.WpaState = SS_FINISH;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE, ("<----- WpaEAPOLKeyAction\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Process Pairwise key 4-way handshaking
+
+       Arguments:
+               pAd     Pointer to our adapter
+               Elem            Message body
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   WpaPairMsg1Action(
+       IN  PRTMP_ADAPTER   pAd,
+       IN  MLME_QUEUE_ELEM *Elem)
+{
+       PHEADER_802_11      pHeader;
+       UCHAR                           *mpool, *PTK, *digest;
+       PUCHAR              pOutBuffer = NULL;
+       UCHAR               Header802_3[14];
+       ULONG               FrameLen = 0;
+       PEAPOL_PACKET       pMsg1;
+       EAPOL_PACKET        Packet;
+       UCHAR               Mic[16];
+
+       DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action ----->\n"));
+
+       // allocate memory pool
+       os_alloc_mem(pAd, (PUCHAR *)&mpool, 256);
+
+       if (mpool == NULL)
+               return;
+
+       // PTK Len = 80.
+       PTK = (UCHAR *) ROUND_UP(mpool, 4);
+       // digest Len = 80.
+       digest = (UCHAR *) ROUND_UP(PTK + 80, 4);
+
+       pHeader = (PHEADER_802_11) Elem->Msg;
+
+       // Process message 1 from authenticator
+       pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+
+       // 1. Save Replay counter, it will use to verify message 3 and construct message 2
+       NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // 2. Save ANonce
+       NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE);
+
+       // Generate random SNonce
+       GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce);
+
+       // Calc PTK(ANonce, SNonce)
+       WpaCountPTK(pAd,
+               pAd->StaCfg.PMK,
+               pAd->StaCfg.ANonce,
+               pAd->CommonCfg.Bssid,
+               pAd->StaCfg.SNonce,
+               pAd->CurrentAddress,
+               PTK,
+               LEN_PTK);
+
+       // Save key to PTK entry
+       NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK);
+
+       // init 802.3 header and Fill Packet
+       MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
+
+       // Zero Message 2 body
+       NdisZeroMemory(&Packet, sizeof(Packet));
+       Packet.ProVer   = EAPOL_VER;
+       Packet.ProType  = EAPOLKey;
+       //
+       // Message 2 as  EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE)
+       //
+       Packet.KeyDesc.Type = WPA1_KEY_DESC;
+       // 1. Key descriptor version and appropriate RSN IE
+       if(pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled)
+       {
+               Packet.KeyDesc.KeyInfo.KeyDescVer = 2;
+       }
+       else      // TKIP
+       {
+               Packet.KeyDesc.KeyInfo.KeyDescVer = 1;
+       }
+
+       // fill in Data Material and its length
+       Packet.KeyDesc.KeyData[0] = IE_WPA;
+       Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len;
+       Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2;
+       NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len);
+
+       // Update packet length after decide Key data payload
+       Packet.Body_Len[1]  = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1];
+
+       // Update Key length
+       Packet.KeyDesc.KeyLength[0] = pMsg1->KeyDesc.KeyLength[0];
+       Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1];
+       // 2. Key Type PeerKey
+       Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
+
+       // 3. KeyMic field presented
+       Packet.KeyDesc.KeyInfo.KeyMic  = 1;
+
+       //Convert to little-endian format.
+       *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
+
+
+       // 4. Fill SNonce
+       NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE);
+
+       // 5. Key Replay Count
+       NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // Send EAPOL(0, 1, 0, 0, 0, P, 0, SNonce, MIC, RSN_IE)
+       // Out buffer for transmitting message 2
+       MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer);  // allocate memory
+       if(pOutBuffer == NULL)
+       {
+               os_free_mem(pAd, mpool);
+               return;
+       }
+       // Prepare EAPOL frame for MIC calculation
+       // Be careful, only EAPOL frame is counted for MIC calculation
+       MakeOutgoingFrame(pOutBuffer,           &FrameLen,
+               Packet.Body_Len[1] + 4,    &Packet,
+               END_OF_ARGS);
+
+       // 6. Prepare and Fill MIC value
+       NdisZeroMemory(Mic, sizeof(Mic));
+       if(pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled)
+       {       // AES
+
+               HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {       // TKIP
+               hmac_md5(PTK,  LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
+       }
+       NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
+
+       //hex_dump("MIC", Mic, LEN_KEY_DESC_MIC);
+
+               MakeOutgoingFrame(pOutBuffer,                   &FrameLen,
+                                               LENGTH_802_3,                           &Header802_3,
+                                               Packet.Body_Len[1] + 4,    &Packet,
+                                               END_OF_ARGS);
+
+
+       // 5. Copy frame to Tx ring and send Msg 2 to authenticator
+       RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE);
+
+       MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
+       os_free_mem(pAd, (PUCHAR)mpool);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action <-----\n"));
+}
+
+VOID Wpa2PairMsg1Action(
+       IN  PRTMP_ADAPTER   pAd,
+       IN  MLME_QUEUE_ELEM *Elem)
+{
+       PHEADER_802_11      pHeader;
+       UCHAR                           *mpool, *PTK, *digest;
+       PUCHAR              pOutBuffer = NULL;
+       UCHAR               Header802_3[14];
+       ULONG               FrameLen = 0;
+       PEAPOL_PACKET       pMsg1;
+       EAPOL_PACKET        Packet;
+       UCHAR               Mic[16];
+
+       DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action ----->\n"));
+
+       // allocate memory pool
+       os_alloc_mem(pAd, (PUCHAR *)&mpool, 256);
+
+       if (mpool == NULL)
+               return;
+
+       // PTK Len = 80.
+       PTK = (UCHAR *) ROUND_UP(mpool, 4);
+       // digest Len = 80.
+       digest = (UCHAR *) ROUND_UP(PTK + 80, 4);
+
+       pHeader = (PHEADER_802_11) Elem->Msg;
+
+       // Process message 1 from authenticator
+               pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+
+       // 1. Save Replay counter, it will use to verify message 3 and construct message 2
+       NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // 2. Save ANonce
+       NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE);
+
+       // Generate random SNonce
+       GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce);
+
+       if(pMsg1->KeyDesc.KeyDataLen[1] > 0 )
+       {
+               // cached PMKID
+       }
+
+       // Calc PTK(ANonce, SNonce)
+       WpaCountPTK(pAd,
+               pAd->StaCfg.PMK,
+               pAd->StaCfg.ANonce,
+               pAd->CommonCfg.Bssid,
+               pAd->StaCfg.SNonce,
+               pAd->CurrentAddress,
+               PTK,
+               LEN_PTK);
+
+       // Save key to PTK entry
+       NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK);
+
+       // init 802.3 header and Fill Packet
+       MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
+
+       // Zero message 2 body
+       NdisZeroMemory(&Packet, sizeof(Packet));
+       Packet.ProVer   = EAPOL_VER;
+       Packet.ProType  = EAPOLKey;
+       //
+       // Message 2 as  EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE)
+       //
+       Packet.KeyDesc.Type = WPA2_KEY_DESC;
+
+       // 1. Key descriptor version and appropriate RSN IE
+       if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
+       {
+               Packet.KeyDesc.KeyInfo.KeyDescVer = 2;
+       }
+       else      // TKIP
+       {
+               Packet.KeyDesc.KeyInfo.KeyDescVer = 1;
+       }
+
+       // fill in Data Material and its length
+       Packet.KeyDesc.KeyData[0] = IE_WPA2;
+       Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len;
+       Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2;
+       NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len);
+
+       // Update packet length after decide Key data payload
+       Packet.Body_Len[1]  = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1];
+
+       // 2. Key Type PeerKey
+       Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
+
+       // 3. KeyMic field presented
+       Packet.KeyDesc.KeyInfo.KeyMic  = 1;
+
+       // Update Key Length
+       Packet.KeyDesc.KeyLength[0] = 0;
+       Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1];
+
+       // 4. Fill SNonce
+       NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE);
+
+       // 5. Key Replay Count
+       NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // Convert to little-endian format.
+       *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
+
+       // Send EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE)
+       // Out buffer for transmitting message 2
+       MlmeAllocateMemory(pAd,  (PUCHAR *)&pOutBuffer);  // allocate memory
+       if(pOutBuffer == NULL)
+       {
+               os_free_mem(pAd, mpool);
+               return;
+       }
+
+       // Prepare EAPOL frame for MIC calculation
+       // Be careful, only EAPOL frame is counted for MIC calculation
+       MakeOutgoingFrame(pOutBuffer,        &FrameLen,
+               Packet.Body_Len[1] + 4, &Packet,
+               END_OF_ARGS);
+
+       // 6. Prepare and Fill MIC value
+       NdisZeroMemory(Mic, sizeof(Mic));
+       if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
+       {
+               // AES
+               HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {
+               hmac_md5(PTK,  LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
+       }
+       NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
+
+
+       // Make  Transmitting frame
+       MakeOutgoingFrame(pOutBuffer,                   &FrameLen,
+                                               LENGTH_802_3,                   &Header802_3,
+                                               Packet.Body_Len[1] + 4, &Packet,
+                                               END_OF_ARGS);
+
+
+       // 5. Copy frame to Tx ring
+       RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE);
+
+       MlmeFreeMemory(pAd, pOutBuffer);
+       os_free_mem(pAd, mpool);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action <-----\n"));
+
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Process Pairwise key 4-way handshaking
+
+       Arguments:
+               pAd     Pointer to our adapter
+               Elem            Message body
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   WpaPairMsg3Action(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      MLME_QUEUE_ELEM *Elem)
+
+{
+       PHEADER_802_11      pHeader;
+       PUCHAR                  pOutBuffer = NULL;
+       UCHAR               Header802_3[14];
+       ULONG                   FrameLen = 0;
+       EAPOL_PACKET        Packet;
+       PEAPOL_PACKET       pMsg3;
+       UCHAR                   Mic[16], OldMic[16];
+       MAC_TABLE_ENTRY         *pEntry = NULL;
+       UCHAR                           skip_offset;
+       KEY_INFO                        peerKeyInfo;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action ----->\n"));
+
+       // 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];
+
+       NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
+       NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO));
+
+       *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo));
+
+
+       // 1. Verify cipher type match
+       if (pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2))
+       {
+               return;
+       }
+       else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1))
+       {
+               return;
+       }
+
+       // Verify RSN IE
+       //if (!RTMPEqualMemory(pMsg3->KeyDesc.KeyData, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len))
+       if (!CheckRSNIE(pAd, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1], &skip_offset))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in Msg 3 of WPA1 4-way handshake!! \n"));
+               hex_dump("The original RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len);
+               hex_dump("The received RSN_IE", pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]);
+               return;
+       }
+       else
+               DBGPRINT(RT_DEBUG_TRACE, ("RSN_IE VALID in Msg 3 of WPA1 4-way handshake!! \n"));
+
+
+       // 2. Check MIC value
+       // Save the MIC and replace with zero
+       NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+       NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+       if(pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled)
+       {
+               // AES
+               UCHAR digest[80];
+
+               HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else    // TKIP
+       {
+               hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic);
+       }
+
+       if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n"));
+               return;
+       }
+       else
+               DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n"));
+
+       // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger
+       if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1)
+               return;
+
+       // Update new replay counter
+       NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // 4. Double check ANonce
+       if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE))
+               return;
+
+       // init 802.3 header and Fill Packet
+       MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
+
+       // Zero Message 4 body
+       NdisZeroMemory(&Packet, sizeof(Packet));
+       Packet.ProVer   = EAPOL_VER;
+       Packet.ProType  = EAPOLKey;
+       Packet.Body_Len[1]  = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE;                // No data field
+
+       //
+       // Message 4 as  EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0)
+       //
+       Packet.KeyDesc.Type = WPA1_KEY_DESC;
+
+       // Key descriptor version and appropriate RSN IE
+       Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer;
+
+       // Update Key Length
+       Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0];
+       Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1];
+
+       // Key Type PeerKey
+       Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
+
+       // KeyMic field presented
+       Packet.KeyDesc.KeyInfo.KeyMic  = 1;
+
+       // In Msg3,  KeyInfo.secure =0 if Group Key HS to come. 1 if no group key HS
+       // Station sends Msg4  KeyInfo.secure should be the same as that in Msg.3
+       Packet.KeyDesc.KeyInfo.Secure= peerKeyInfo.Secure;
+
+       // Convert to little-endian format.
+       *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
+
+       // Key Replay count
+       NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // Out buffer for transmitting message 4
+       MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer);  // allocate memory
+       if(pOutBuffer == NULL)
+               return;
+
+       // Prepare EAPOL frame for MIC calculation
+       // Be careful, only EAPOL frame is counted for MIC calculation
+       MakeOutgoingFrame(pOutBuffer,           &FrameLen,
+               Packet.Body_Len[1] + 4,    &Packet,
+               END_OF_ARGS);
+
+       // Prepare and Fill MIC value
+       NdisZeroMemory(Mic, sizeof(Mic));
+       if(pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled)
+       {
+               // AES
+               UCHAR digest[80];
+
+               HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {
+               hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
+       }
+       NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
+
+       // Update PTK
+       // Prepare pair-wise key information into shared key table
+       NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY));
+       pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK;
+    NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK);
+       NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK);
+       NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK);
+
+       // Decide its ChiperAlg
+       if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled)
+               pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP;
+       else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled)
+               pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES;
+       else
+               pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE;
+
+       // Update these related information to MAC_TABLE_ENTRY
+       pEntry = &pAd->MacTab.Content[BSSID_WCID];
+       NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK);
+       NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK);
+       NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK);
+       pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg;
+
+       // Update pairwise key information to ASIC Shared Key Table
+       AsicAddSharedKeyEntry(pAd,
+                                                 BSS0,
+                                                 0,
+                                                 pAd->SharedKey[BSS0][0].CipherAlg,
+                                                 pAd->SharedKey[BSS0][0].Key,
+                                                 pAd->SharedKey[BSS0][0].TxMic,
+                                                 pAd->SharedKey[BSS0][0].RxMic);
+
+       // Update ASIC WCID attribute table and IVEIV table
+       RTMPAddWcidAttributeEntry(pAd,
+                                                         BSS0,
+                                                         0,
+                                                         pAd->SharedKey[BSS0][0].CipherAlg,
+                                                         pEntry);
+
+       // Make transmitting frame
+       MakeOutgoingFrame(pOutBuffer,                   &FrameLen,
+                                               LENGTH_802_3,                   &Header802_3,
+                                               Packet.Body_Len[1] + 4, &Packet,
+                                               END_OF_ARGS);
+
+
+       // Copy frame to Tx ring and Send Message 4 to authenticator
+       RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE);
+
+       MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action <-----\n"));
+}
+
+VOID    Wpa2PairMsg3Action(
+       IN  PRTMP_ADAPTER   pAd,
+       IN  MLME_QUEUE_ELEM *Elem)
+
+{
+       PHEADER_802_11      pHeader;
+       PUCHAR              pOutBuffer = NULL;
+       UCHAR               Header802_3[14];
+       ULONG               FrameLen = 0;
+       EAPOL_PACKET        Packet;
+       PEAPOL_PACKET       pMsg3;
+       UCHAR               Mic[16], OldMic[16];
+       UCHAR               *mpool, *KEYDATA, *digest;
+       UCHAR               Key[32];
+       MAC_TABLE_ENTRY         *pEntry = NULL;
+       KEY_INFO                        peerKeyInfo;
+
+       // allocate memory
+       os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024);
+
+       if(mpool == NULL)
+               return;
+
+       // KEYDATA Len = 512.
+       KEYDATA = (UCHAR *) ROUND_UP(mpool, 4);
+       // digest Len = 80.
+       digest = (UCHAR *) ROUND_UP(KEYDATA + 512, 4);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg3Action ----->\n"));
+
+       pHeader = (PHEADER_802_11) Elem->Msg;
+
+       // Process message 3 frame.
+       pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
+
+       NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
+       NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO));
+
+       *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo));
+
+       // 1. Verify cipher type match
+       if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer!= 2))
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+       else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1))
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+
+       // 2. Check MIC value
+       // Save the MIC and replace with zero
+       NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+       NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+       if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
+       {
+               // AES
+               HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {
+               hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic);
+       }
+
+       if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n"));
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+       else
+               DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n"));
+
+       // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger
+       if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1)
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+
+       // Update new replay counter
+       NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // 4. Double check ANonce
+       if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE))
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+
+       // Obtain GTK
+       // 5. Decrypt GTK from Key Data
+       DBGPRINT_RAW(RT_DEBUG_TRACE, ("EKD = %d\n", peerKeyInfo.EKD_DL));
+       if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
+       {
+               // Decrypt AES GTK
+               AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pMsg3->KeyDesc.KeyDataLen[1],pMsg3->KeyDesc.KeyData);
+       }
+       else      // TKIP
+       {
+               INT i;
+               // Decrypt TKIP GTK
+               // Construct 32 bytes RC4 Key
+               NdisMoveMemory(Key, pMsg3->KeyDesc.KeyIv, 16);
+               NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16);
+               ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32);
+               //discard first 256 bytes
+               for(i = 0; i < 256; i++)
+                       ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT);
+               // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not
+               ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]);
+       }
+
+       if (!ParseKeyData(pAd, KEYDATA, pMsg3->KeyDesc.KeyDataLen[1], 1))
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+
+       // Update GTK to ASIC
+       // Update group key information to ASIC Shared Key Table
+       AsicAddSharedKeyEntry(pAd,
+                                                 BSS0,
+                                                 pAd->StaCfg.DefaultKeyId,
+                                                 pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg,
+                                                 pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key,
+                                                 pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic,
+                                                 pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic);
+
+       // Update ASIC WCID attribute table and IVEIV table
+       RTMPAddWcidAttributeEntry(pAd,
+                                                         BSS0,
+                                                         pAd->StaCfg.DefaultKeyId,
+                                                         pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg,
+                                                         NULL);
+
+       // init 802.3 header and Fill Packet
+       MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
+
+       // Zero message 4 body
+       NdisZeroMemory(&Packet, sizeof(Packet));
+       Packet.ProVer   = EAPOL_VER;
+       Packet.ProType  = EAPOLKey;
+       Packet.Body_Len[1]      = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE;            // No data field
+
+       //
+       // Message 4 as  EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0)
+       //
+       Packet.KeyDesc.Type = WPA2_KEY_DESC;
+
+       // Key descriptor version and appropriate RSN IE
+       Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer;
+
+       // Update Key Length
+       Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0];
+       Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1];
+
+       // Key Type PeerKey
+       Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
+
+       // KeyMic field presented
+       Packet.KeyDesc.KeyInfo.KeyMic  = 1;
+       Packet.KeyDesc.KeyInfo.Secure = 1;
+
+       // Convert to little-endian format.
+       *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
+
+       // Key Replay count
+       NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // Out buffer for transmitting message 4
+       MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer);  // allocate memory
+       if(pOutBuffer == NULL)
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+
+       // Prepare EAPOL frame for MIC calculation
+       // Be careful, only EAPOL frame is counted for MIC calculation
+       MakeOutgoingFrame(pOutBuffer,           &FrameLen,
+               Packet.Body_Len[1] + 4,    &Packet,
+               END_OF_ARGS);
+
+       // Prepare and Fill MIC value
+       NdisZeroMemory(Mic, sizeof(Mic));
+       if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
+       {
+               // AES
+               HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {
+               hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
+       }
+       NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
+
+       // Update PTK
+       // Prepare pair-wise key information into shared key table
+       NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY));
+       pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK;
+    NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK);
+       NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK);
+       NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK);
+
+       // Decide its ChiperAlg
+       if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled)
+               pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP;
+       else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled)
+               pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES;
+       else
+               pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE;
+
+       // Update these related information to MAC_TABLE_ENTRY
+       pEntry = &pAd->MacTab.Content[BSSID_WCID];
+       NdisMoveMemory(&pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK);
+       NdisMoveMemory(&pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK);
+       NdisMoveMemory(&pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK);
+       pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg;
+
+       // Update pairwise key information to ASIC Shared Key Table
+       AsicAddSharedKeyEntry(pAd,
+                                                 BSS0,
+                                                 0,
+                                                 pAd->SharedKey[BSS0][0].CipherAlg,
+                                                 pAd->SharedKey[BSS0][0].Key,
+                                                 pAd->SharedKey[BSS0][0].TxMic,
+                                                 pAd->SharedKey[BSS0][0].RxMic);
+
+       // Update ASIC WCID attribute table and IVEIV table
+       RTMPAddWcidAttributeEntry(pAd,
+                                                         BSS0,
+                                                         0,
+                                                         pAd->SharedKey[BSS0][0].CipherAlg,
+                                                         pEntry);
+
+       // Make  Transmitting frame
+       MakeOutgoingFrame(pOutBuffer,                   &FrameLen,
+                                               LENGTH_802_3,                   &Header802_3,
+                                               Packet.Body_Len[1] + 4, &Packet,
+                                               END_OF_ARGS);
+
+
+       // Copy frame to Tx ring and Send Message 4 to authenticator
+       RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE);
+
+       // set 802.1x port control
+       //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
+       STA_PORT_SECURED(pAd);
+
+    // Indicate Connected for GUI
+    pAd->IndicateMediaState = NdisMediaStateConnected;
+
+       MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
+       os_free_mem(pAd, (PUCHAR)mpool);
+
+
+       // send wireless event - for set key done WPA2
+       if (pAd->CommonCfg.bWirelessEvent)
+               RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, BSS0, 0);
+
+       DBGPRINT(RT_DEBUG_ERROR, ("Wpa2PairMsg3Action <-----\n"));
+
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Process Group key 2-way handshaking
+
+       Arguments:
+               pAd     Pointer to our adapter
+               Elem            Message body
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   WpaGroupMsg1Action(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      MLME_QUEUE_ELEM *Elem)
+
+{
+       PUCHAR              pOutBuffer = NULL;
+       UCHAR               Header802_3[14];
+       ULONG               FrameLen = 0;
+       EAPOL_PACKET        Packet;
+       PEAPOL_PACKET       pGroup;
+       UCHAR               *mpool, *digest, *KEYDATA;
+       UCHAR               Mic[16], OldMic[16];
+       UCHAR               GTK[32], Key[32];
+       KEY_INFO                        peerKeyInfo;
+
+       // allocate memory
+       os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024);
+
+       if(mpool == NULL)
+               return;
+
+       // digest Len = 80.
+       digest = (UCHAR *) ROUND_UP(mpool, 4);
+       // KEYDATA Len = 512.
+       KEYDATA = (UCHAR *) ROUND_UP(digest + 80, 4);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action ----->\n"));
+
+       // 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];
+
+       NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
+       NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pGroup->KeyDesc.KeyInfo, sizeof(KEY_INFO));
+
+       *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo));
+
+       // 0. Check cipher type match
+       if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2))
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+       else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1))
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+
+       // 1. Verify Replay counter
+       //    Check Replay Counter, it has to be larger than last one. No need to be exact one larger
+       if(RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1)
+       {
+               os_free_mem(pAd, (PUCHAR)mpool);
+               return;
+       }
+
+       // Update new replay counter
+       NdisMoveMemory(pAd->StaCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // 2. Verify MIC is valid
+       // Save the MIC and replace with zero
+       NdisMoveMemory(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+       NdisZeroMemory(pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
+
+       if(pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled)
+       {       // AES
+               HMAC_SHA1((PUCHAR) pGroup, pGroup->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {       // TKIP
+               hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Body_Len[1] + 4, Mic);
+       }
+
+       if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n"));
+               MlmeFreeMemory(pAd, (PUCHAR)mpool);
+               return;
+       }
+       else
+               DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n"));
+
+
+       // 3. Decrypt GTK from Key Data
+       if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
+       {
+               // Decrypt AES GTK
+               AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA,  pGroup->KeyDesc.KeyDataLen[1], pGroup->KeyDesc.KeyData);
+       }
+       else    // TKIP
+       {
+               INT i;
+
+               // Decrypt TKIP GTK
+               // Construct 32 bytes RC4 Key
+               NdisMoveMemory(Key, pGroup->KeyDesc.KeyIv, 16);
+               NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16);
+               ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32);
+               //discard first 256 bytes
+               for(i = 0; i < 256; i++)
+                       ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT);
+               // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not
+               ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pGroup->KeyDesc.KeyData, pGroup->KeyDesc.KeyDataLen[1]);
+       }
+
+       // Process decrypted key data material
+       // Parse keyData to handle KDE format for WPA2PSK
+       if (peerKeyInfo.EKD_DL)
+       {
+               if (!ParseKeyData(pAd, KEYDATA, pGroup->KeyDesc.KeyDataLen[1], 0))
+               {
+                       os_free_mem(pAd, (PUCHAR)mpool);
+                       return;
+               }
+       }
+       else    // WPAPSK
+       {
+               // set key material, TxMic and RxMic for WPAPSK
+               NdisMoveMemory(GTK, KEYDATA, 32);
+               NdisMoveMemory(pAd->StaCfg.GTK, GTK, 32);
+               pAd->StaCfg.DefaultKeyId = peerKeyInfo.KeyIndex;
+
+               // Prepare pair-wise key information into shared key table
+               NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY));
+               pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK;
+               NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, GTK, LEN_TKIP_EK);
+               NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &GTK[16], LEN_TKIP_RXMICK);
+               NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &GTK[24], LEN_TKIP_TXMICK);
+
+               // Update Shared Key CipherAlg
+               pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE;
+               if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled)
+                       pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP;
+               else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)
+                       pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES;
+
+       //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK);
+       }
+
+       // Update group key information to ASIC Shared Key Table
+       AsicAddSharedKeyEntry(pAd,
+                                                 BSS0,
+                                                 pAd->StaCfg.DefaultKeyId,
+                                                 pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg,
+                                                 pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key,
+                                                 pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic,
+                                                 pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic);
+
+       // Update ASIC WCID attribute table and IVEIV table
+       RTMPAddWcidAttributeEntry(pAd,
+                                                         BSS0,
+                                                         pAd->StaCfg.DefaultKeyId,
+                                                         pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg,
+                                                         NULL);
+
+       // set 802.1x port control
+       //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
+       STA_PORT_SECURED(pAd);
+
+    // Indicate Connected for GUI
+    pAd->IndicateMediaState = NdisMediaStateConnected;
+
+       // init header and Fill Packet
+       MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
+
+       // Zero Group message 1 body
+       NdisZeroMemory(&Packet, sizeof(Packet));
+       Packet.ProVer   = EAPOL_VER;
+       Packet.ProType  = EAPOLKey;
+       Packet.Body_Len[1]  = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE;                // No data field
+
+       //
+       // Group Message 2 as  EAPOL-Key(1,0,0,0,G,0,0,MIC,0)
+       //
+       if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
+       {
+               Packet.KeyDesc.Type = WPA2_KEY_DESC;
+       }
+       else
+       {
+               Packet.KeyDesc.Type = WPA1_KEY_DESC;
+       }
+
+       // Key descriptor version and appropriate RSN IE
+       Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer;
+
+       // Update Key Length
+       Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0];
+       Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1];
+
+       // Key Index as G-Msg 1
+       if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)
+               Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex;
+
+       // Key Type Group key
+       Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY;
+
+       // KeyMic field presented
+       Packet.KeyDesc.KeyInfo.KeyMic  = 1;
+
+       // Secure bit
+       Packet.KeyDesc.KeyInfo.Secure  = 1;
+
+       // Convert to little-endian format.
+       *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
+
+       // Key Replay count
+       NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
+
+       // Out buffer for transmitting group message 2
+       MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer);  // allocate memory
+       if(pOutBuffer == NULL)
+       {
+               MlmeFreeMemory(pAd, (PUCHAR)mpool);
+               return;
+       }
+
+       // Prepare EAPOL frame for MIC calculation
+       // Be careful, only EAPOL frame is counted for MIC calculation
+       MakeOutgoingFrame(pOutBuffer,           &FrameLen,
+               Packet.Body_Len[1] + 4,    &Packet,
+               END_OF_ARGS);
+
+       // Prepare and Fill MIC value
+       NdisZeroMemory(Mic, sizeof(Mic));
+       if(pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled)
+       {
+               // AES
+               HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {
+               hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
+       }
+       NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
+
+
+       MakeOutgoingFrame(pOutBuffer,                   &FrameLen,
+                                               LENGTH_802_3,                   &Header802_3,
+                                               Packet.Body_Len[1] + 4, &Packet,
+                                               END_OF_ARGS);
+
+
+       // 5. Copy frame to Tx ring and prepare for encryption
+       RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE);
+
+       // 6 Free allocated memory
+       MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
+       os_free_mem(pAd, (PUCHAR)mpool);
+
+       // send wireless event - for set key done WPA2
+       if (pAd->CommonCfg.bWirelessEvent)
+               RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Init WPA MAC header
+
+       Arguments:
+               pAd     Pointer to our adapter
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   WpaMacHeaderInit(
+       IN              PRTMP_ADAPTER   pAd,
+       IN OUT  PHEADER_802_11  pHdr80211,
+       IN              UCHAR                   wep,
+       IN              PUCHAR              pAddr1)
+{
+       NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11));
+       pHdr80211->FC.Type      = BTYPE_DATA;
+       pHdr80211->FC.ToDs      = 1;
+       if (wep == 1)
+               pHdr80211->FC.Wep = 1;
+
+        //     Addr1: BSSID, Addr2: SA, Addr3: DA
+       COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1);
+       COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress);
+       COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid);
+       pHdr80211->Sequence =   pAd->Sequence;
+}
+
+/*
+       ========================================================================
+
+       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  PUCHAR          pHeader802_3,
+    IN  UINT            HdrLen,
+       IN  PUCHAR          pData,
+    IN  UINT            DataLen,
+    IN BOOLEAN                 is4wayFrame)
+
+{
+       NDIS_STATUS     Status;
+       PNDIS_PACKET    pPacket;
+       UCHAR   Index;
+
+       do
+       {
+               // 1. build a NDIS packet and call RTMPSendPacket();
+               //    be careful about how/when to release this internal allocated NDIS PACKET buffer
+               Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen);
+               if (Status != NDIS_STATUS_SUCCESS)
+                       break;
+
+               if (is4wayFrame)
+                       RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1);
+               else
+                       RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0);
+
+               // 2. send out the packet
+               Status = STASendPacket(pAd, pPacket);
+               if(Status == NDIS_STATUS_SUCCESS)
+               {
+                       // Dequeue one frame from TxSwQueue0..3 queue and process it
+                       // There are three place calling dequeue for TX ring.
+                       // 1. Here, right after queueing the frame.
+                       // 2. At the end of TxRingTxDone service routine.
+                       // 3. Upon NDIS call RTMPSendPackets
+                       if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) &&
+                               (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)))
+                       {
+                               for(Index = 0; Index < 5; Index ++)
+                                       if(pAd->TxSwQueue[Index].Number > 0)
+                                               RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS);
+                       }
+               }
+       } while(FALSE);
+
+}
+
+/*
+    ========================================================================
+
+    Routine Description:
+    Check Sanity RSN IE form AP
+
+    Arguments:
+
+    Return Value:
+
+
+    ========================================================================
+*/
+BOOLEAN CheckRSNIE(
+       IN  PRTMP_ADAPTER   pAd,
+       IN  PUCHAR          pData,
+       IN  UCHAR           DataLen,
+       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 ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) &&
+                               (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) &&
+                               (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2)))
+                       {
+                                       DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2)));
+                                       result = TRUE;
+                       }
+
+                       *Offset += (pEid->Len + 2);
+               }
+               // WPA2 RSN IE
+               else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)))
+               {
+                       if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) &&
+                               (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) &&
+                               (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2)))
+                       {
+                                       DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2)));
+                                       result = TRUE;
+                       }
+
+                       *Offset += (pEid->Len + 2);
+               }
+               else
+               {
+                       break;
+               }
+
+               pVIE += (pEid->Len + 2);
+               len  -= (pEid->Len + 2);
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset));
+
+       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 ParseKeyData(
+       IN  PRTMP_ADAPTER   pAd,
+       IN  PUCHAR          pKeyData,
+       IN  UCHAR           KeyDataLen,
+       IN      UCHAR                   bPairewise)
+{
+    PKDE_ENCAP          pKDE = NULL;
+    PUCHAR              pMyKeyData = pKeyData;
+    UCHAR               KeyDataLength = KeyDataLen;
+    UCHAR               GTKLEN;
+       UCHAR                           skip_offset;
+
+       // Verify The RSN IE contained in Pairewise-Msg 3 and skip it
+       if (bPairewise)
+    {
+               // Check RSN IE whether it is WPA2/WPA2PSK
+               if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset))
+               {
+                       DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n"));
+                       hex_dump("Get KEYDATA :", pKeyData, KeyDataLen);
+                       return FALSE;
+       }
+       else
+               {
+                       // skip RSN IE
+                       pMyKeyData += skip_offset;
+                       KeyDataLength -= skip_offset;
+
+                       //DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset));
+               }
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength));
+
+       // Parse EKD format
+       if (KeyDataLength >= 8)
+    {
+        pKDE = (PKDE_ENCAP) pMyKeyData;
+    }
+       else
+    {
+               DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n"));
+        return FALSE;
+    }
+
+
+       // Sanity check - shared key index should not be 0
+       if (pKDE->GTKEncap.Kid == 0)
+    {
+        DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n"));
+        return FALSE;
+    }
+
+       // Sanity check - KED length
+       if (KeyDataLength < (pKDE->Len + 2))
+    {
+        DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n"));
+        return FALSE;
+    }
+
+       // Get GTK length - refer to IEEE 802.11i-2004 p.82
+       GTKLEN = pKDE->Len -6;
+
+       if (GTKLEN < LEN_AES_KEY)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN));
+        return FALSE;
+       }
+       else
+               DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN));
+
+       // Update GTK
+       // set key material, TxMic and RxMic for WPAPSK
+       NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32);
+       pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid;
+
+       // Update shared key table
+       NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY));
+       pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK;
+       NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK);
+       NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK);
+       NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK);
+
+       // Update Shared Key CipherAlg
+       pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE;
+       if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled)
+               pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP;
+       else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)
+               pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES;
+
+       return TRUE;
+
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Cisco CCKM PRF function
+
+       Arguments:
+               key                             Cisco Base Transient Key (BTK)
+               key_len                 The key length of the BTK
+               data                    Ruquest Number(RN) + BSSID
+               data_len                The length of the data
+               output                  Store for PTK(Pairwise transient keys)
+               len                             The length of the output
+       Return Value:
+               None
+
+       Note:
+               802.1i  Annex F.9
+
+       ========================================================================
+*/
+VOID CCKMPRF(
+       IN      UCHAR   *key,
+       IN      INT             key_len,
+       IN      UCHAR   *data,
+       IN      INT             data_len,
+       OUT     UCHAR   *output,
+       IN      INT             len)
+{
+       INT             i;
+       UCHAR   input[1024];
+       INT             currentindex = 0;
+       INT             total_len;
+
+       NdisMoveMemory(input, data, data_len);
+       total_len = data_len;
+       input[total_len] = 0;
+       total_len++;
+       for     (i = 0; i <     (len + 19) / 20; i++)
+       {
+               HMAC_SHA1(input, total_len,     key, key_len, &output[currentindex]);
+               currentindex += 20;
+               input[total_len - 1]++;
+       }
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Process MIC error indication and record MIC error timer.
+
+       Arguments:
+               pAd     Pointer to our adapter
+               pWpaKey                 Pointer to the WPA key structure
+
+       Return Value:
+               None
+
+       IRQL = DISPATCH_LEVEL
+
+       Note:
+
+       ========================================================================
+*/
+VOID   RTMPReportMicError(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      PCIPHER_KEY     pWpaKey)
+{
+       ULONG   Now;
+    UCHAR   unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1:0);
+
+       // Record Last MIC error time and count
+       Now = jiffies;
+       if (pAd->StaCfg.MicErrCnt == 0)
+       {
+               pAd->StaCfg.MicErrCnt++;
+               pAd->StaCfg.LastMicErrorTime = Now;
+        NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8);
+       }
+       else if (pAd->StaCfg.MicErrCnt == 1)
+       {
+               if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now)
+               {
+                       // Update Last MIC error time, this did not violate two MIC errors within 60 seconds
+                       pAd->StaCfg.LastMicErrorTime = Now;
+               }
+               else
+               {
+
+                       if (pAd->CommonCfg.bWirelessEvent)
+                               RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
+
+                       pAd->StaCfg.LastMicErrorTime = Now;
+                       // Violate MIC error counts, MIC countermeasures kicks in
+                       pAd->StaCfg.MicErrCnt++;
+                       // We shall block all reception
+                       // We shall clean all Tx ring and disassoicate from AP after next EAPOL frame
+                       //
+                       // No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets
+                       // if pAd->StaCfg.MicErrCnt greater than 2.
+                       //
+                       // RTMPRingCleanUp(pAd, QID_AC_BK);
+                       // RTMPRingCleanUp(pAd, QID_AC_BE);
+                       // RTMPRingCleanUp(pAd, QID_AC_VI);
+                       // RTMPRingCleanUp(pAd, QID_AC_VO);
+                       // RTMPRingCleanUp(pAd, QID_HCCA);
+               }
+       }
+       else
+       {
+               // MIC error count >= 2
+               // This should not happen
+               ;
+       }
+    MlmeEnqueue(pAd,
+                               MLME_CNTL_STATE_MACHINE,
+                               OID_802_11_MIC_FAILURE_REPORT_FRAME,
+                               1,
+                               &unicastKey);
+
+    if (pAd->StaCfg.MicErrCnt == 2)
+    {
+        RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100);
+    }
+}
+
+
+#ifdef WPA_SUPPLICANT_SUPPORT
+#define        LENGTH_EAP_H    4
+// If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)).
+INT        WpaCheckEapCode(
+       IN  PRTMP_ADAPTER               pAd,
+       IN  PUCHAR                              pFrame,
+       IN  USHORT                              FrameLen,
+       IN  USHORT                              OffSet)
+{
+
+       PUCHAR  pData;
+       INT     result = 0;
+
+       if( FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H )
+               return result;
+
+       pData = pFrame + OffSet; // skip offset bytes
+
+       if(*(pData+1) == EAPPacket)     // 802.1x header - Packet Type
+       {
+                result = *(pData+4);           // EAP header - Code
+       }
+
+       return result;
+}
+
+VOID    WpaSendMicFailureToWpaSupplicant(
+    IN  PRTMP_ADAPTER    pAd,
+    IN  BOOLEAN          bUnicast)
+{
+    union iwreq_data    wrqu;
+    char custom[IW_CUSTOM_MAX] = {0};
+
+    sprintf(custom, "MLME-MICHAELMICFAILURE.indication");
+    if (bUnicast)
+        sprintf(custom, "%s unicast", custom);
+    wrqu.data.length = strlen(custom);
+    wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom);
+
+    return;
+}
+#endif // WPA_SUPPLICANT_SUPPORT //
+
+VOID   WpaMicFailureReportFrame(
+       IN  PRTMP_ADAPTER   pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+{
+       PUCHAR              pOutBuffer = NULL;
+       UCHAR               Header802_3[14];
+       ULONG               FrameLen = 0;
+       EAPOL_PACKET        Packet;
+       UCHAR               Mic[16];
+    BOOLEAN             bUnicast;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n"));
+
+    bUnicast = (Elem->Msg[0] == 1 ? TRUE:FALSE);
+       pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER);
+
+       // init 802.3 header and Fill Packet
+       MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
+
+       NdisZeroMemory(&Packet, sizeof(Packet));
+       Packet.ProVer   = EAPOL_VER;
+       Packet.ProType  = EAPOLKey;
+
+       Packet.KeyDesc.Type = WPA1_KEY_DESC;
+
+    // Request field presented
+    Packet.KeyDesc.KeyInfo.Request = 1;
+
+       if(pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled)
+       {
+               Packet.KeyDesc.KeyInfo.KeyDescVer = 2;
+       }
+       else      // TKIP
+       {
+               Packet.KeyDesc.KeyInfo.KeyDescVer = 1;
+       }
+
+    Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY);
+
+       // KeyMic field presented
+       Packet.KeyDesc.KeyInfo.KeyMic  = 1;
+
+    // Error field presented
+       Packet.KeyDesc.KeyInfo.Error  = 1;
+
+       // Update packet length after decide Key data payload
+       Packet.Body_Len[1]  = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE;
+
+       // Key Replay Count
+       NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY);
+    inc_byte_array(pAd->StaCfg.ReplayCounter, 8);
+
+       // Convert to little-endian format.
+       *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
+
+
+       MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer);  // allocate memory
+       if(pOutBuffer == NULL)
+       {
+               return;
+       }
+
+       // Prepare EAPOL frame for MIC calculation
+       // Be careful, only EAPOL frame is counted for MIC calculation
+       MakeOutgoingFrame(pOutBuffer,               &FrameLen,
+                             Packet.Body_Len[1] + 4,   &Packet,
+                             END_OF_ARGS);
+
+       // Prepare and Fill MIC value
+       NdisZeroMemory(Mic, sizeof(Mic));
+       if(pAd->StaCfg.WepStatus  == Ndis802_11Encryption3Enabled)
+       {       // AES
+        UCHAR digest[20] = {0};
+               HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {       // TKIP
+               hmac_md5(pAd->StaCfg.PTK,  LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
+       }
+       NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
+
+    MakeOutgoingFrame(pOutBuffer,              &FrameLen,
+                               LENGTH_802_3,                           &Header802_3,
+                               Packet.Body_Len[1] + 4,     &Packet,
+                               END_OF_ARGS);
+
+       // opy frame to Tx ring and send MIC failure report frame to authenticator
+       RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE);
+
+       MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n"));
+}
+
+/** from wpa_supplicant
+ * inc_byte_array - Increment arbitrary length byte array by one
+ * @counter: Pointer to byte array
+ * @len: Length of the counter in bytes
+ *
+ * This function increments the last 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_byte_array(UCHAR *counter, int len)
+{
+       int pos = len - 1;
+       while (pos >= 0) {
+               counter[pos]++;
+               if (counter[pos] != 0)
+                       break;
+               pos--;
+       }
+}
+
+VOID WpaDisassocApAndBlockAssoc(
+    IN PVOID SystemSpecific1,
+    IN PVOID FunctionContext,
+    IN PVOID SystemSpecific2,
+    IN PVOID SystemSpecific3)
+{
+    RTMP_ADAPTER                *pAd = (PRTMP_ADAPTER)FunctionContext;
+    MLME_DISASSOC_REQ_STRUCT    DisassocReq;
+
+       // disassoc from current AP first
+       DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n"));
+       DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE);
+       MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
+
+       pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
+       pAd->StaCfg.bBlockAssoc = TRUE;
+}
+