diff options
Diffstat (limited to 'drivers/staging/rt2860/common/cmm_wpa.c')
-rw-r--r-- | drivers/staging/rt2860/common/cmm_wpa.c | 1606 |
1 files changed, 1606 insertions, 0 deletions
diff --git a/drivers/staging/rt2860/common/cmm_wpa.c b/drivers/staging/rt2860/common/cmm_wpa.c new file mode 100644 index 000000000000..81c332ac2524 --- /dev/null +++ b/drivers/staging/rt2860/common/cmm_wpa.c @@ -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; + +} + |