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