]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/staging/rt3070/common/cmm_wpa.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / staging / rt3070 / common / cmm_wpa.c
diff --git a/drivers/staging/rt3070/common/cmm_wpa.c b/drivers/staging/rt3070/common/cmm_wpa.c
new file mode 100644 (file)
index 0000000..81c332a
--- /dev/null
@@ -0,0 +1,1606 @@
+/*
+ *************************************************************************
+ * 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"
+// WPA OUI
+UCHAR          OUI_WPA_NONE_AKM[4]             = {0x00, 0x50, 0xF2, 0x00};
+UCHAR       OUI_WPA_VERSION[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_8021X_AKM[4]       = {0x00, 0x50, 0xF2, 0x01};
+UCHAR       OUI_WPA_PSK_AKM[4]      = {0x00, 0x50, 0xF2, 0x02};
+// WPA2 OUI
+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};
+// MSA OUI
+UCHAR          OUI_MSA_8021X_AKM[4]    = {0x00, 0x0F, 0xAC, 0x05};             // Not yet final - IEEE 802.11s-D1.06
+UCHAR          OUI_MSA_PSK_AKM[4]      = {0x00, 0x0F, 0xAC, 0x06};             // Not yet final - IEEE 802.11s-D1.06
+
+/*
+       ========================================================================
+
+       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++)
+       {
+               HMAC_SHA1(input, total_len,     key, key_len, &output[currentindex]);
+               currentindex += 20;
+
+               // update the last octet
+               input[total_len - 1]++;
+       }
+    os_free_mem(NULL, input);
+}
+
+/*
+       ========================================================================
+
+       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 WpaCountPTK(
+       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("concatenation=", concatenation, 76);
+
+       // Use PRF to generate PTK
+       PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, 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 RTMPInsertRsnIeCipher(
+       IN  PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   ElementID,
+       IN      UINT                    WepStatus,
+       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_cipher->ucast[0].oui + 4, 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_cipher->ucast[0].oui + 4, 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 RTMPInsertRsnIeAKM(
+       IN  PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   ElementID,
+       IN      UINT                    AuthMode,
+       IN      UCHAR                   apidx,
+       OUT     PUCHAR                  pRsnIe,
+       OUT     UCHAR                   *rsn_len)
+{
+       RSNIE_AUTH              *pRsnie_auth;
+
+       pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len));
+
+       // decide WPA2 or WPA1
+       if (ElementID == Wpa2Ie)
+       {
+               switch (AuthMode)
+        {
+            case Ndis802_11AuthModeWPA2:
+            case Ndis802_11AuthModeWPA1WPA2:
+                pRsnie_auth->acount = 1;
+                       NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4);
+                break;
+
+            case Ndis802_11AuthModeWPA2PSK:
+            case Ndis802_11AuthModeWPA1PSKWPA2PSK:
+                pRsnie_auth->acount = 1;
+                       NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4);
+                break;
+        }
+       }
+       else
+       {
+               switch (AuthMode)
+        {
+            case Ndis802_11AuthModeWPA:
+            case Ndis802_11AuthModeWPA1WPA2:
+                pRsnie_auth->acount = 1;
+                NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4);
+                break;
+
+            case Ndis802_11AuthModeWPAPSK:
+            case Ndis802_11AuthModeWPA1PSKWPA2PSK:
+                pRsnie_auth->acount = 1;
+                NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4);
+                break;
+
+                       case Ndis802_11AuthModeWPANone:
+                pRsnie_auth->acount = 1;
+                NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4);
+                break;
+        }
+       }
+
+       pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount);
+
+       (*rsn_len) += sizeof(RSNIE_AUTH);       // update current RSNIE length
+
+}
+
+/*
+       ========================================================================
+
+       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 RTMPInsertRsnIeCap(
+       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));
+
+
+       pRSN_Cap->word = cpu2le16(pRSN_Cap->word);
+
+       (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length
+
+}
+
+
+/*
+       ========================================================================
+
+       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
+       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;
+
+       {
+#ifdef CONFIG_STA_SUPPORT
+               IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+               {
+#ifdef WPA_SUPPLICANT_SUPPORT
+                       if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE)
+                       {
+                               if (AuthMode < Ndis802_11AuthModeWPA)
+                                       return;
+                       }
+                       else
+#endif // WPA_SUPPLICANT_SUPPORT //
+                       {
+                               // Support WPAPSK or WPA2PSK in STA-Infra mode
+                               // Support WPANone in STA-Adhoc mode
+                               if ((AuthMode != Ndis802_11AuthModeWPAPSK) &&
+                                       (AuthMode != Ndis802_11AuthModeWPA2PSK) &&
+                                       (AuthMode != Ndis802_11AuthModeWPANone)
+                                       )
+                                       return;
+                       }
+
+                       DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n"));
+
+                       // Zero RSNIE context
+                       pAd->StaCfg.RSNIE_Len = 0;
+                       NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE);
+
+                       // Pointer to RSNIE
+                       rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len;
+                       pRsnIe = pAd->StaCfg.RSN_IE;
+
+                       bMixCipher = pAd->StaCfg.bMixCipher;
+               }
+#endif // CONFIG_STA_SUPPORT //
+       }
+
+       // 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;
+       else
+               PrimaryRsnie = Wpa2Ie;
+
+       {
+               // Build the primary RSNIE
+               // 1. insert cipher suite
+               RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset);
+
+               // 2. insert AKM
+               RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset);
+
+               // 3. insert capability
+               RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset);
+       }
+
+       // 4. update the RSNIE length
+       *rsnielen_cur_p = p_offset;
+
+       hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p));
+
+
+}
+
+/*
+    ==========================================================================
+    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;
+
+
+    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))
+    {
+        pData += 2;
+    }
+    else
+        return FALSE;
+
+    switch (*(pData+1))
+    {
+        case EAPPacket:
+                       Body_len = (*(pData+2)<<8) | (*(pData+3));
+            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;
+}
+
+
+/*
+    ==========================================================================
+    Description:
+        ENCRYPT AES GTK before sending in EAPOL frame.
+        AES GTK length = 128 bit,  so fix blocks for aes-key-wrap as 2 in this function.
+        This function references to RFC 3394 for aes key wrap algorithm.
+    Return:
+    ==========================================================================
+*/
+VOID AES_GTK_KEY_WRAP(
+    IN UCHAR    *key,
+    IN UCHAR    *plaintext,
+    IN UCHAR    p_len,
+    OUT UCHAR   *ciphertext)
+{
+    UCHAR       A[8], BIN[16], BOUT[16];
+    UCHAR       R[512];
+    INT         num_blocks = p_len/8;   // unit:64bits
+    INT         i, j;
+    aes_context aesctx;
+    UCHAR       xor;
+
+    rtmp_aes_set_key(&aesctx, key, 128);
+
+    // Init IA
+    for (i = 0; i < 8; i++)
+        A[i] = 0xa6;
+
+    //Input plaintext
+    for (i = 0; i < num_blocks; i++)
+    {
+        for (j = 0 ; j < 8; j++)
+            R[8 * (i + 1) + j] = plaintext[8 * i + j];
+    }
+
+    // Key Mix
+    for (j = 0; j < 6; j++)
+    {
+        for(i = 1; i <= num_blocks; i++)
+        {
+            //phase 1
+            NdisMoveMemory(BIN, A, 8);
+            NdisMoveMemory(&BIN[8], &R[8 * i], 8);
+            rtmp_aes_encrypt(&aesctx, BIN, BOUT);
+
+            NdisMoveMemory(A, &BOUT[0], 8);
+            xor = num_blocks * j + i;
+            A[7] = BOUT[7] ^ xor;
+            NdisMoveMemory(&R[8 * i], &BOUT[8], 8);
+        }
+    }
+
+    // Output ciphertext
+    NdisMoveMemory(ciphertext, A, 8);
+
+    for (i = 1; i <= num_blocks; i++)
+    {
+        for (j = 0 ; j < 8; j++)
+            ciphertext[8 * i + j] = R[8 * i + j];
+    }
+}
+
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Misc function to decrypt AES body
+
+       Arguments:
+
+       Return Value:
+
+       Note:
+               This function references to     RFC     3394 for aes key unwrap algorithm.
+
+       ========================================================================
+*/
+VOID   AES_GTK_KEY_UNWRAP(
+       IN      UCHAR   *key,
+       OUT     UCHAR   *plaintext,
+       IN      UCHAR    c_len,
+       IN      UCHAR   *ciphertext)
+
+{
+       UCHAR       A[8], BIN[16], BOUT[16];
+       UCHAR       xor;
+       INT         i, j;
+       aes_context aesctx;
+       UCHAR       *R;
+       INT         num_blocks = c_len/8;       // unit:64bits
+
+
+       os_alloc_mem(NULL, (PUCHAR *)&R, 512);
+
+       if (R == NULL)
+    {
+        DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n"));
+        return;
+    } /* End of if */
+
+       // Initialize
+       NdisMoveMemory(A, ciphertext, 8);
+       //Input plaintext
+       for(i = 0; i < (c_len-8); i++)
+       {
+               R[ i] = ciphertext[i + 8];
+       }
+
+       rtmp_aes_set_key(&aesctx, key, 128);
+
+       for(j = 5; j >= 0; j--)
+       {
+               for(i = (num_blocks-1); i > 0; i--)
+               {
+                       xor = (num_blocks -1 )* j + i;
+                       NdisMoveMemory(BIN, A, 8);
+                       BIN[7] = A[7] ^ xor;
+                       NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8);
+                       rtmp_aes_decrypt(&aesctx, BIN, BOUT);
+                       NdisMoveMemory(A, &BOUT[0], 8);
+                       NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8);
+               }
+       }
+
+       // OUTPUT
+       for(i = 0; i < c_len; i++)
+       {
+               plaintext[i] = R[i];
+       }
+
+
+       os_free_mem(NULL, R);
+}
+
+/*
+    ==========================================================================
+    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
+
+    ==========================================================================
+*/
+CHAR *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
+               else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)))
+               {
+                       if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2 || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) &&
+                               (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) &&
+                               (pEntry->RSNIE_Len == (pEid->Len + 2))/* ToDo-AlbertY for mesh*/)
+                       {
+                                       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)
+{
+    PKDE_ENCAP          pKDE = NULL;
+    PUCHAR              pMyKeyData = pKeyData;
+    UCHAR               KeyDataLength = KeyDataLen;
+    UCHAR               GTKLEN = 0;
+       UCHAR                           DefaultIdx = 0;
+       UCHAR                           skip_offset;
+
+       // 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)
+    {
+               // Check RSN IE whether it is WPA2/WPA2PSK
+               if (!RTMPCheckRSNIE(pAd, pKeyData, KeyDataLen, pEntry, &skip_offset))
+               {
+                       // send wireless event - for RSN IE different
+                       if (pAd->CommonCfg.bWirelessEvent)
+                               RTMPSendWirelessEvent(pAd, IW_RSNIE_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0);
+
+               DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in msg %d of 4-way handshake!\n", MsgType));
+                       hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen);
+                       hex_dump("Desired RSN_IE ", pEntry->RSN_IE, pEntry->RSNIE_Len);
+
+                       return FALSE;
+       }
+       else
+               {
+                       if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3)
+                       {
+                               // 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));
+
+       // Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2
+       if (bWPA2 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1))
+       {
+               if (KeyDataLength >= 8) // KDE format exclude GTK length
+       {
+               pKDE = (PKDE_ENCAP) pMyKeyData;
+
+
+                       DefaultIdx = pKDE->GTKEncap.Kid;
+
+                       // 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_ERROR, ("ERROR: KDE format length is too short \n"));
+               return FALSE;
+       }
+
+               DBGPRINT(RT_DEBUG_TRACE, ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n", DefaultIdx, GTKLEN));
+               // skip it
+               pMyKeyData += 8;
+               KeyDataLength -= 8;
+
+       }
+       else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1)
+       {
+               DefaultIdx = GroupKeyIndex;
+               DBGPRINT(RT_DEBUG_TRACE, ("GTK DefaultKeyID=%d \n", DefaultIdx));
+       }
+
+       // Sanity check - shared key index must be 1 ~ 3
+       if (DefaultIdx < 1 || 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_STA_SUPPORT
+       // Todo
+#endif // CONFIG_STA_SUPPORT //
+
+       return TRUE;
+
+}
+
+
+/*
+       ========================================================================
+
+       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      PRTMP_ADAPTER           pAd,
+    IN         UCHAR                           AuthMode,
+    IN         UCHAR                           WepStatus,
+    IN         UCHAR                           GroupKeyWepStatus,
+    IN         UCHAR                           MsgType,
+    IN UCHAR                           DefaultKeyIdx,
+    IN         UCHAR                           *ReplayCounter,
+       IN      UCHAR                           *KeyNonce,
+       IN      UCHAR                           *TxRSC,
+       IN      UCHAR                           *PTK,
+       IN      UCHAR                           *GTK,
+       IN      UCHAR                           *RSNIE,
+       IN      UCHAR                           RSNIE_Len,
+    OUT PEAPOL_PACKET       pMsg)
+{
+       BOOLEAN bWPA2 = FALSE;
+
+       // Choose WPA2 or not
+       if ((AuthMode == Ndis802_11AuthModeWPA2) || (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
+       pMsg->Body_Len[1] = LEN_EAPOL_KEY_MSG;
+
+       // Fill in EAPoL descriptor
+       if (bWPA2)
+               pMsg->KeyDesc.Type = WPA2_KEY_DESC;
+       else
+               pMsg->KeyDesc.Type = WPA1_KEY_DESC;
+
+       // Fill in Key information, refer to IEEE Std 802.11i-2004 page 78
+       // When either the pairwise or the group cipher is AES, the DESC_TYPE_AES(2) shall be used.
+       pMsg->KeyDesc.KeyInfo.KeyDescVer =
+               (((WepStatus == Ndis802_11Encryption3Enabled) || (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP));
+
+       // 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;
+    }
+
+       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 (MsgType >= EAPOL_GROUP_MSG_1)
+               {
+                       // the length of group key cipher
+                       pMsg->KeyDesc.KeyLength[1] = ((GroupKeyWepStatus == Ndis802_11Encryption2Enabled) ? TKIP_GTK_LENGTH : LEN_AES_KEY);
+               }
+               else
+               {
+                       // the length of pairwise key cipher
+                       pMsg->KeyDesc.KeyLength[1] = ((WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY : LEN_AES_KEY);
+               }
+       }
+
+       // Fill in replay counter
+    NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, ReplayCounter, 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(pAd,
+                                                 AuthMode,
+                                                 WepStatus,
+                                                 GroupKeyWepStatus,
+                                                 MsgType,
+                                                 DefaultKeyIdx,
+                                                 bWPA2,
+                                                 PTK,
+                                                 GTK,
+                                                 RSNIE,
+                                                 RSNIE_Len,
+                                                 pMsg);
+
+       // Calculate MIC and fill in KeyMic Field except Pairwise Msg 1.
+       if (MsgType != EAPOL_PAIR_MSG_1)
+       {
+               CalculateMIC(pAd, WepStatus, PTK, pMsg);
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE, ("===> ConstructEapolMsg for %s %s\n", ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType)));
+       DBGPRINT(RT_DEBUG_TRACE, ("          Body length = %d \n", pMsg->Body_Len[1]));
+       DBGPRINT(RT_DEBUG_TRACE, ("          Key length  = %d \n", pMsg->KeyDesc.KeyLength[1]));
+
+
+}
+
+/*
+       ========================================================================
+
+       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      PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   AuthMode,
+       IN      UCHAR                   WepStatus,
+       IN      UCHAR                   GroupKeyWepStatus,
+       IN      UCHAR                   MsgType,
+       IN      UCHAR                   DefaultKeyIdx,
+       IN      BOOLEAN                 bWPA2Capable,
+       IN      UCHAR                   *PTK,
+       IN      UCHAR                   *GTK,
+       IN      UCHAR                   *RSNIE,
+       IN      UCHAR                   RSNIE_LEN,
+       OUT PEAPOL_PACKET   pMsg)
+{
+       UCHAR           *mpool, *Key_Data, *Rc4GTK;
+       UCHAR       ekey[(LEN_KEY_DESC_IV+LEN_EAP_EK)];
+       UCHAR           data_offset;
+
+
+       if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2)
+               return;
+
+       // allocate memory pool
+       os_alloc_mem(pAd, (PUCHAR *)&mpool, 1500);
+
+    if (mpool == NULL)
+               return;
+
+       /* Rc4GTK Len = 512 */
+       Rc4GTK = (UCHAR *) ROUND_UP(mpool, 4);
+       /* Key_Data Len = 512 */
+       Key_Data = (UCHAR *) ROUND_UP(Rc4GTK + 512, 4);
+
+       NdisZeroMemory(Key_Data, 512);
+       pMsg->KeyDesc.KeyDataLen[1] = 0;
+       data_offset = 0;
+
+       // Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3
+       if (RSNIE_LEN && ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3)))
+       {
+               if (bWPA2Capable)
+                       Key_Data[data_offset + 0] = IE_WPA2;
+               else
+                       Key_Data[data_offset + 0] = IE_WPA;
+
+        Key_Data[data_offset + 1] = RSNIE_LEN;
+               NdisMoveMemory(&Key_Data[data_offset + 2], RSNIE, RSNIE_LEN);
+               data_offset += (2 + RSNIE_LEN);
+       }
+
+       // Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2
+       if (bWPA2Capable && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1)))
+       {
+               // Key Data Encapsulation (KDE) format - 802.11i-2004  Figure-43w and Table-20h
+        Key_Data[data_offset + 0] = 0xDD;
+
+               if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)
+               {
+                       Key_Data[data_offset + 1] = 0x16;// 4+2+16(OUI+DataType+DataField)
+               }
+               else
+               {
+                       Key_Data[data_offset + 1] = 0x26;// 4+2+32(OUI+DataType+DataField)
+               }
+
+        Key_Data[data_offset + 2] = 0x00;
+        Key_Data[data_offset + 3] = 0x0F;
+        Key_Data[data_offset + 4] = 0xAC;
+        Key_Data[data_offset + 5] = 0x01;
+
+               // GTK KDE format - 802.11i-2004  Figure-43x
+        Key_Data[data_offset + 6] = (DefaultKeyIdx & 0x03);
+        Key_Data[data_offset + 7] = 0x00;      // Reserved Byte
+
+               data_offset += 8;
+       }
+
+
+       // Encapsulate GTK and encrypt the key-data field with KEK.
+       // Only for pairwise_msg3_WPA2 and group_msg1
+       if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) || (MsgType == EAPOL_GROUP_MSG_1))
+       {
+               // Fill in GTK
+               if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)
+               {
+                       NdisMoveMemory(&Key_Data[data_offset], GTK, LEN_AES_KEY);
+                       data_offset += LEN_AES_KEY;
+               }
+               else
+               {
+                       NdisMoveMemory(&Key_Data[data_offset], GTK, TKIP_GTK_LENGTH);
+                       data_offset += TKIP_GTK_LENGTH;
+               }
+
+               // Still dont know why, but if not append will occur "GTK not include in MSG3"
+               // Patch for compatibility between zero config and funk
+               if (MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable)
+               {
+                       if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)
+                       {
+                               Key_Data[data_offset + 0] = 0xDD;
+                               Key_Data[data_offset + 1] = 0;
+                               data_offset += 2;
+                       }
+                       else
+                       {
+                               Key_Data[data_offset + 0] = 0xDD;
+                               Key_Data[data_offset + 1] = 0;
+                               Key_Data[data_offset + 2] = 0;
+                               Key_Data[data_offset + 3] = 0;
+                               Key_Data[data_offset + 4] = 0;
+                               Key_Data[data_offset + 5] = 0;
+                               data_offset += 6;
+                       }
+               }
+
+               // Encrypt the data material in key data field
+               if (WepStatus == Ndis802_11Encryption3Enabled)
+               {
+                       AES_GTK_KEY_WRAP(&PTK[16], Key_Data, data_offset, Rc4GTK);
+            // AES wrap function will grow 8 bytes in length
+            data_offset += 8;
+               }
+               else
+               {
+                       // PREPARE Encrypted  "Key DATA" field.  (Encrypt GTK with RC4, usinf PTK[16]->[31] as Key, IV-field as IV)
+                       // put TxTsc in Key RSC field
+                       pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32;   //Init crc32.
+
+                       // ekey is the contanetion of IV-field, and PTK[16]->PTK[31]
+                       NdisMoveMemory(ekey, pMsg->KeyDesc.KeyIv, LEN_KEY_DESC_IV);
+                       NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &PTK[16], LEN_EAP_EK);
+                       ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, ekey, sizeof(ekey));  //INIT SBOX, KEYLEN+3(IV)
+                       pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, Key_Data, data_offset);
+                       WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK, Key_Data, data_offset);
+               }
+
+               NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset);
+       }
+       else
+       {
+               NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset);
+       }
+
+       // set key data length field and total length
+       pMsg->KeyDesc.KeyDataLen[1] = data_offset;
+    pMsg->Body_Len[1] += data_offset;
+
+       os_free_mem(pAd, 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:
+
+       ========================================================================
+*/
+VOID   CalculateMIC(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   PeerWepStatus,
+       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(pAd, (PUCHAR *)&OutBuffer, 512);
+
+    if (OutBuffer == NULL)
+    {
+               DBGPRINT(RT_DEBUG_ERROR, ("!!!CalculateMIC: no memory!!!\n"));
+               return;
+    }
+
+       // make a frame for calculating MIC.
+    MakeOutgoingFrame(OutBuffer,               &FrameLen,
+                      pMsg->Body_Len[1] + 4,   pMsg,
+                      END_OF_ARGS);
+
+       NdisZeroMemory(mic, sizeof(mic));
+
+       // Calculate MIC
+    if (PeerWepStatus == Ndis802_11Encryption3Enabled)
+       {
+               HMAC_SHA1(OutBuffer,  FrameLen, PTK, LEN_EAP_MICK, digest);
+               NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC);
+       }
+       else
+       {
+               hmac_md5(PTK,  LEN_EAP_MICK, OutBuffer, FrameLen, mic);
+       }
+
+       // store the calculated MIC
+       NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC);
+
+       os_free_mem(pAd, OutBuffer);
+}
+
+/*
+       ========================================================================
+
+       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    RTMPSoftDecryptBroadCastData(
+       IN      PRTMP_ADAPTER                                   pAd,
+       IN      RX_BLK                                                  *pRxBlk,
+       IN  NDIS_802_11_ENCRYPTION_STATUS       GroupCipher,
+       IN  PCIPHER_KEY                                         pShard_key)
+{
+       PRXWI_STRUC                     pRxWI = pRxBlk->pRxWI;
+
+
+
+       // handle WEP decryption
+       if (GroupCipher == Ndis802_11Encryption1Enabled)
+    {
+               if (RTMPSoftDecryptWEP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, pShard_key))
+               {
+
+                       //Minus IV[4] & ICV[4]
+                       pRxWI->MPDUtotalByteCount -= 8;
+               }
+               else
+               {
+                       DBGPRINT(RT_DEBUG_ERROR, ("ERROR : Software decrypt WEP data fails.\n"));
+                       // give up this frame
+                       return NDIS_STATUS_FAILURE;
+               }
+       }
+       // handle TKIP decryption
+       else if (GroupCipher == Ndis802_11Encryption2Enabled)
+       {
+               if (RTMPSoftDecryptTKIP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0, pShard_key))
+               {
+
+                       //Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV
+                       pRxWI->MPDUtotalByteCount -= 20;
+               }
+        else
+               {
+                       DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptTKIP Failed\n"));
+                       // give up this frame
+                       return NDIS_STATUS_FAILURE;
+        }
+       }
+       // handle AES decryption
+       else if (GroupCipher == Ndis802_11Encryption3Enabled)
+       {
+               if (RTMPSoftDecryptAES(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount , pShard_key))
+               {
+
+                       //8 bytes MIC, 8 bytes IV/EIV (CCMP Header)
+                       pRxWI->MPDUtotalByteCount -= 16;
+               }
+               else
+               {
+                       DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptAES Failed\n"));
+                       // give up this frame
+                       return NDIS_STATUS_FAILURE;
+               }
+       }
+       else
+       {
+               // give up this frame
+               return NDIS_STATUS_FAILURE;
+       }
+
+       return NDIS_STATUS_SUCCESS;
+
+}
+