2092 lines
62 KiB
C
2092 lines
62 KiB
C
/*
|
|
*************************************************************************
|
|
* 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
|
|
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
|
|
STA_PORT_SECURED(pAd);
|
|
|
|
// Indicate Connected for GUI
|
|
pAd->IndicateMediaState = NdisMediaStateConnected;
|
|
|
|
// init header and Fill Packet
|
|
MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
|
|
|
|
// Zero Group message 1 body
|
|
NdisZeroMemory(&Packet, sizeof(Packet));
|
|
Packet.ProVer = EAPOL_VER;
|
|
Packet.ProType = EAPOLKey;
|
|
Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field
|
|
|
|
//
|
|
// Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0)
|
|
//
|
|
if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
|
|
{
|
|
Packet.KeyDesc.Type = WPA2_KEY_DESC;
|
|
}
|
|
else
|
|
{
|
|
Packet.KeyDesc.Type = WPA1_KEY_DESC;
|
|
}
|
|
|
|
// Key descriptor version and appropriate RSN IE
|
|
Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer;
|
|
|
|
// Update Key Length
|
|
Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0];
|
|
Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1];
|
|
|
|
// Key Index as G-Msg 1
|
|
if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)
|
|
Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex;
|
|
|
|
// Key Type Group key
|
|
Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY;
|
|
|
|
// KeyMic field presented
|
|
Packet.KeyDesc.KeyInfo.KeyMic = 1;
|
|
|
|
// Secure bit
|
|
Packet.KeyDesc.KeyInfo.Secure = 1;
|
|
|
|
// Convert to little-endian format.
|
|
*((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
|
|
|
|
// Key Replay count
|
|
NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
|
|
|
|
// Out buffer for transmitting group message 2
|
|
MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory
|
|
if(pOutBuffer == NULL)
|
|
{
|
|
MlmeFreeMemory(pAd, (PUCHAR)mpool);
|
|
return;
|
|
}
|
|
|
|
// Prepare EAPOL frame for MIC calculation
|
|
// Be careful, only EAPOL frame is counted for MIC calculation
|
|
MakeOutgoingFrame(pOutBuffer, &FrameLen,
|
|
Packet.Body_Len[1] + 4, &Packet,
|
|
END_OF_ARGS);
|
|
|
|
// Prepare and Fill MIC value
|
|
NdisZeroMemory(Mic, sizeof(Mic));
|
|
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
|
|
{
|
|
// AES
|
|
HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
|
|
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
|
|
}
|
|
else
|
|
{
|
|
hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
|
|
}
|
|
NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
|
|
|
|
|
|
MakeOutgoingFrame(pOutBuffer, &FrameLen,
|
|
LENGTH_802_3, &Header802_3,
|
|
Packet.Body_Len[1] + 4, &Packet,
|
|
END_OF_ARGS);
|
|
|
|
|
|
// 5. Copy frame to Tx ring and prepare for encryption
|
|
RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE);
|
|
|
|
// 6 Free allocated memory
|
|
MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
|
|
os_free_mem(pAd, (PUCHAR)mpool);
|
|
|
|
// send wireless event - for set key done WPA2
|
|
if (pAd->CommonCfg.bWirelessEvent)
|
|
RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n"));
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Init WPA MAC header
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
VOID WpaMacHeaderInit(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN OUT PHEADER_802_11 pHdr80211,
|
|
IN UCHAR wep,
|
|
IN PUCHAR pAddr1)
|
|
{
|
|
NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11));
|
|
pHdr80211->FC.Type = BTYPE_DATA;
|
|
pHdr80211->FC.ToDs = 1;
|
|
if (wep == 1)
|
|
pHdr80211->FC.Wep = 1;
|
|
|
|
// Addr1: BSSID, Addr2: SA, Addr3: DA
|
|
COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1);
|
|
COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress);
|
|
COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid);
|
|
pHdr80211->Sequence = pAd->Sequence;
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Copy frame from waiting queue into relative ring buffer and set
|
|
appropriate ASIC register to kick hardware encryption before really
|
|
sent out to air.
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
PNDIS_PACKET Pointer to outgoing Ndis frame
|
|
NumberOfFrag Number of fragment required
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPToWirelessSta(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pHeader802_3,
|
|
IN UINT HdrLen,
|
|
IN PUCHAR pData,
|
|
IN UINT DataLen,
|
|
IN BOOLEAN is4wayFrame)
|
|
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET pPacket;
|
|
UCHAR Index;
|
|
|
|
do
|
|
{
|
|
// 1. build a NDIS packet and call RTMPSendPacket();
|
|
// be careful about how/when to release this internal allocated NDIS PACKET buffer
|
|
Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
break;
|
|
|
|
if (is4wayFrame)
|
|
RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1);
|
|
else
|
|
RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0);
|
|
|
|
// 2. send out the packet
|
|
Status = STASendPacket(pAd, pPacket);
|
|
if(Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
// Dequeue one frame from TxSwQueue0..3 queue and process it
|
|
// There are three place calling dequeue for TX ring.
|
|
// 1. Here, right after queueing the frame.
|
|
// 2. At the end of TxRingTxDone service routine.
|
|
// 3. Upon NDIS call RTMPSendPackets
|
|
if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) &&
|
|
(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)))
|
|
{
|
|
for(Index = 0; Index < 5; Index ++)
|
|
if(pAd->TxSwQueue[Index].Number > 0)
|
|
RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS);
|
|
}
|
|
}
|
|
} while(FALSE);
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Check Sanity RSN IE form AP
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
========================================================================
|
|
*/
|
|
BOOLEAN CheckRSNIE(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pData,
|
|
IN UCHAR DataLen,
|
|
OUT UCHAR *Offset)
|
|
{
|
|
PUCHAR pVIE;
|
|
UCHAR len;
|
|
PEID_STRUCT pEid;
|
|
BOOLEAN result = FALSE;
|
|
|
|
pVIE = pData;
|
|
len = DataLen;
|
|
*Offset = 0;
|
|
|
|
while (len > sizeof(RSNIE2))
|
|
{
|
|
pEid = (PEID_STRUCT) pVIE;
|
|
// WPA RSN IE
|
|
if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)))
|
|
{
|
|
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) &&
|
|
(NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) &&
|
|
(pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2)))
|
|
{
|
|
DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2)));
|
|
result = TRUE;
|
|
}
|
|
|
|
*Offset += (pEid->Len + 2);
|
|
}
|
|
// WPA2 RSN IE
|
|
else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)))
|
|
{
|
|
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) &&
|
|
(NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) &&
|
|
(pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2)))
|
|
{
|
|
DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2)));
|
|
result = TRUE;
|
|
}
|
|
|
|
*Offset += (pEid->Len + 2);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
pVIE += (pEid->Len + 2);
|
|
len -= (pEid->Len + 2);
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK.
|
|
GTK is encaptulated in KDE format at p.83 802.11i D10
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
802.11i D10
|
|
|
|
========================================================================
|
|
*/
|
|
BOOLEAN ParseKeyData(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pKeyData,
|
|
IN UCHAR KeyDataLen,
|
|
IN UCHAR bPairewise)
|
|
{
|
|
PKDE_ENCAP pKDE = NULL;
|
|
PUCHAR pMyKeyData = pKeyData;
|
|
UCHAR KeyDataLength = KeyDataLen;
|
|
UCHAR GTKLEN;
|
|
UCHAR skip_offset;
|
|
|
|
// Verify The RSN IE contained in Pairewise-Msg 3 and skip it
|
|
if (bPairewise)
|
|
{
|
|
// Check RSN IE whether it is WPA2/WPA2PSK
|
|
if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n"));
|
|
hex_dump("Get KEYDATA :", pKeyData, KeyDataLen);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// skip RSN IE
|
|
pMyKeyData += skip_offset;
|
|
KeyDataLength -= skip_offset;
|
|
|
|
//DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset));
|
|
}
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength));
|
|
|
|
// Parse EKD format
|
|
if (KeyDataLength >= 8)
|
|
{
|
|
pKDE = (PKDE_ENCAP) pMyKeyData;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Sanity check - shared key index should not be 0
|
|
if (pKDE->GTKEncap.Kid == 0)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Sanity check - KED length
|
|
if (KeyDataLength < (pKDE->Len + 2))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Get GTK length - refer to IEEE 802.11i-2004 p.82
|
|
GTKLEN = pKDE->Len -6;
|
|
|
|
if (GTKLEN < LEN_AES_KEY)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN));
|
|
return FALSE;
|
|
}
|
|
else
|
|
DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN));
|
|
|
|
// Update GTK
|
|
// set key material, TxMic and RxMic for WPAPSK
|
|
NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32);
|
|
pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid;
|
|
|
|
// Update shared key table
|
|
NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY));
|
|
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK;
|
|
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK);
|
|
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK);
|
|
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK);
|
|
|
|
// Update Shared Key CipherAlg
|
|
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE;
|
|
if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled)
|
|
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP;
|
|
else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)
|
|
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES;
|
|
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++;
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
#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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|