mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
6aed5295ae
Signed-off-by: Joe Perches <joe@perches.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
3014 lines
85 KiB
C
3014 lines
85 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"
|
|
/* WPA OUI */
|
|
u8 OUI_WPA_NONE_AKM[4] = { 0x00, 0x50, 0xF2, 0x00 };
|
|
u8 OUI_WPA_VERSION[4] = { 0x00, 0x50, 0xF2, 0x01 };
|
|
u8 OUI_WPA_WEP40[4] = { 0x00, 0x50, 0xF2, 0x01 };
|
|
u8 OUI_WPA_TKIP[4] = { 0x00, 0x50, 0xF2, 0x02 };
|
|
u8 OUI_WPA_CCMP[4] = { 0x00, 0x50, 0xF2, 0x04 };
|
|
u8 OUI_WPA_WEP104[4] = { 0x00, 0x50, 0xF2, 0x05 };
|
|
u8 OUI_WPA_8021X_AKM[4] = { 0x00, 0x50, 0xF2, 0x01 };
|
|
u8 OUI_WPA_PSK_AKM[4] = { 0x00, 0x50, 0xF2, 0x02 };
|
|
|
|
/* WPA2 OUI */
|
|
u8 OUI_WPA2_WEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 };
|
|
u8 OUI_WPA2_TKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 };
|
|
u8 OUI_WPA2_CCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 };
|
|
u8 OUI_WPA2_8021X_AKM[4] = { 0x00, 0x0F, 0xAC, 0x01 };
|
|
u8 OUI_WPA2_PSK_AKM[4] = { 0x00, 0x0F, 0xAC, 0x02 };
|
|
u8 OUI_WPA2_WEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 };
|
|
|
|
static void ConstructEapolKeyData(struct rt_mac_table_entry *pEntry,
|
|
u8 GroupKeyWepStatus,
|
|
u8 keyDescVer,
|
|
u8 MsgType,
|
|
u8 DefaultKeyIdx,
|
|
u8 * GTK,
|
|
u8 * RSNIE,
|
|
u8 RSNIE_LEN, struct rt_eapol_packet * pMsg);
|
|
|
|
static void CalculateMIC(u8 KeyDescVer,
|
|
u8 * PTK, struct rt_eapol_packet * pMsg);
|
|
|
|
static void WpaEAPPacketAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem);
|
|
|
|
static void WpaEAPOLASFAlertAction(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mlme_queue_elem *Elem);
|
|
|
|
static void WpaEAPOLLogoffAction(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mlme_queue_elem *Elem);
|
|
|
|
static void WpaEAPOLStartAction(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mlme_queue_elem *Elem);
|
|
|
|
static void WpaEAPOLKeyAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem);
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
association state machine init, including state transition and timer init
|
|
Parameters:
|
|
S - pointer to the association state machine
|
|
==========================================================================
|
|
*/
|
|
void WpaStateMachineInit(struct rt_rtmp_adapter *pAd,
|
|
struct rt_state_machine *S, OUT STATE_MACHINE_FUNC Trans[])
|
|
{
|
|
StateMachineInit(S, (STATE_MACHINE_FUNC *) Trans, MAX_WPA_PTK_STATE,
|
|
MAX_WPA_MSG, (STATE_MACHINE_FUNC) Drop, WPA_PTK,
|
|
WPA_MACHINE_BASE);
|
|
|
|
StateMachineSetAction(S, WPA_PTK, MT2_EAPPacket,
|
|
(STATE_MACHINE_FUNC) WpaEAPPacketAction);
|
|
StateMachineSetAction(S, WPA_PTK, MT2_EAPOLStart,
|
|
(STATE_MACHINE_FUNC) WpaEAPOLStartAction);
|
|
StateMachineSetAction(S, WPA_PTK, MT2_EAPOLLogoff,
|
|
(STATE_MACHINE_FUNC) WpaEAPOLLogoffAction);
|
|
StateMachineSetAction(S, WPA_PTK, MT2_EAPOLKey,
|
|
(STATE_MACHINE_FUNC) WpaEAPOLKeyAction);
|
|
StateMachineSetAction(S, WPA_PTK, MT2_EAPOLASFAlert,
|
|
(STATE_MACHINE_FUNC) WpaEAPOLASFAlertAction);
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
this is state machine function.
|
|
When receiving EAP packets which is for 802.1x authentication use.
|
|
Not use in PSK case
|
|
Return:
|
|
==========================================================================
|
|
*/
|
|
void WpaEAPPacketAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
}
|
|
|
|
void WpaEAPOLASFAlertAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
}
|
|
|
|
void WpaEAPOLLogoffAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Start 4-way HS when rcv EAPOL_START which may create by our driver in assoc.c
|
|
Return:
|
|
==========================================================================
|
|
*/
|
|
void WpaEAPOLStartAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
struct rt_mac_table_entry *pEntry;
|
|
struct rt_header_802_11 * pHeader;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLStartAction ===> \n"));
|
|
|
|
pHeader = (struct rt_header_802_11 *) Elem->Msg;
|
|
|
|
/*For normaol PSK, we enqueue an EAPOL-Start command to trigger the process. */
|
|
if (Elem->MsgLen == 6)
|
|
pEntry = MacTableLookup(pAd, Elem->Msg);
|
|
else {
|
|
pEntry = MacTableLookup(pAd, pHeader->Addr2);
|
|
}
|
|
|
|
if (pEntry) {
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
(" PortSecured(%d), WpaState(%d), AuthMode(%d), PMKID_CacheIdx(%d) \n",
|
|
pEntry->PortSecured, pEntry->WpaState,
|
|
pEntry->AuthMode, pEntry->PMKID_CacheIdx));
|
|
|
|
if ((pEntry->PortSecured == WPA_802_1X_PORT_NOT_SECURED)
|
|
&& (pEntry->WpaState < AS_PTKSTART)
|
|
&& ((pEntry->AuthMode == Ndis802_11AuthModeWPAPSK)
|
|
|| (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)
|
|
|| ((pEntry->AuthMode == Ndis802_11AuthModeWPA2)
|
|
&& (pEntry->PMKID_CacheIdx != ENTRY_NOT_FOUND)))) {
|
|
pEntry->PrivacyFilter = Ndis802_11PrivFilter8021xWEP;
|
|
pEntry->WpaState = AS_INITPSK;
|
|
pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED;
|
|
NdisZeroMemory(pEntry->R_Counter,
|
|
sizeof(pEntry->R_Counter));
|
|
pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR;
|
|
|
|
WPAStart4WayHS(pAd, pEntry, PEER_MSG1_RETRY_EXEC_INTV);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
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(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
struct rt_mac_table_entry *pEntry;
|
|
struct rt_header_802_11 * pHeader;
|
|
struct rt_eapol_packet * pEapol_packet;
|
|
struct rt_key_info peerKeyInfo;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLKeyAction ===>\n"));
|
|
|
|
pHeader = (struct rt_header_802_11 *) Elem->Msg;
|
|
pEapol_packet =
|
|
(struct rt_eapol_packet *) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
|
|
|
|
NdisZeroMemory((u8 *)& peerKeyInfo, sizeof(peerKeyInfo));
|
|
NdisMoveMemory((u8 *)& peerKeyInfo,
|
|
(u8 *)& pEapol_packet->KeyDesc.KeyInfo,
|
|
sizeof(struct rt_key_info));
|
|
|
|
hex_dump("Received Eapol frame", (unsigned char *)pEapol_packet,
|
|
(Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H));
|
|
|
|
*((u16 *) & peerKeyInfo) = cpu2le16(*((u16 *) & peerKeyInfo));
|
|
|
|
do {
|
|
pEntry = MacTableLookup(pAd, pHeader->Addr2);
|
|
|
|
if (!pEntry
|
|
|| ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
|
|
break;
|
|
|
|
if (pEntry->AuthMode < Ndis802_11AuthModeWPA)
|
|
break;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("Receive EAPoL-Key frame from STA %02X-%02X-%02X-%02X-%02X-%02X\n",
|
|
PRINT_MAC(pEntry->Addr)));
|
|
|
|
if (((pEapol_packet->ProVer != EAPOL_VER)
|
|
&& (pEapol_packet->ProVer != EAPOL_VER2))
|
|
|| ((pEapol_packet->KeyDesc.Type != WPA1_KEY_DESC)
|
|
&& (pEapol_packet->KeyDesc.Type != WPA2_KEY_DESC))) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("Key descripter does not match with WPA rule\n"));
|
|
break;
|
|
}
|
|
/* The value 1 shall be used for all EAPOL-Key frames to and from a STA when */
|
|
/* neither the group nor pairwise ciphers are CCMP for Key Descriptor 1. */
|
|
if ((pEntry->WepStatus == Ndis802_11Encryption2Enabled)
|
|
&& (peerKeyInfo.KeyDescVer != DESC_TYPE_TKIP)) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("Key descripter version not match(TKIP) \n"));
|
|
break;
|
|
}
|
|
/* The value 2 shall be used for all EAPOL-Key frames to and from a STA when */
|
|
/* either the pairwise or the group cipher is AES-CCMP for Key Descriptor 2. */
|
|
else if ((pEntry->WepStatus == Ndis802_11Encryption3Enabled)
|
|
&& (peerKeyInfo.KeyDescVer != DESC_TYPE_AES)) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("Key descripter version not match(AES) \n"));
|
|
break;
|
|
}
|
|
/* Check if this STA is in class 3 state and the WPA state is started */
|
|
if ((pEntry->Sst == SST_ASSOC)
|
|
&& (pEntry->WpaState >= AS_INITPSK)) {
|
|
/* Check the Key Ack (bit 7) of the Key Information to determine the Authenticator */
|
|
/* or not. */
|
|
/* An EAPOL-Key frame that is sent by the Supplicant in response to an EAPOL- */
|
|
/* Key frame from the Authenticator must not have the Ack bit set. */
|
|
if (peerKeyInfo.KeyAck == 1) {
|
|
/* The frame is snet by Authenticator. */
|
|
/* So the Supplicant side shall handle this. */
|
|
|
|
if ((peerKeyInfo.Secure == 0)
|
|
&& (peerKeyInfo.Request == 0)
|
|
&& (peerKeyInfo.Error == 0)
|
|
&& (peerKeyInfo.KeyType == PAIRWISEKEY)) {
|
|
/* Process 1. the message 1 of 4-way HS in WPA or WPA2 */
|
|
/* EAPOL-Key(0,0,1,0,P,0,0,ANonce,0,DataKD_M1) */
|
|
/* 2. the message 3 of 4-way HS in WPA */
|
|
/* EAPOL-Key(0,1,1,1,P,0,KeyRSC,ANonce,MIC,DataKD_M3) */
|
|
if (peerKeyInfo.KeyMic == 0)
|
|
PeerPairMsg1Action(pAd, pEntry,
|
|
Elem);
|
|
else
|
|
PeerPairMsg3Action(pAd, pEntry,
|
|
Elem);
|
|
} else if ((peerKeyInfo.Secure == 1)
|
|
&& (peerKeyInfo.KeyMic == 1)
|
|
&& (peerKeyInfo.Request == 0)
|
|
&& (peerKeyInfo.Error == 0)) {
|
|
/* Process 1. the message 3 of 4-way HS in WPA2 */
|
|
/* EAPOL-Key(1,1,1,1,P,0,KeyRSC,ANonce,MIC,DataKD_M3) */
|
|
/* 2. the message 1 of group KS in WPA or WPA2 */
|
|
/* EAPOL-Key(1,1,1,0,G,0,Key RSC,0, MIC,GTK[N]) */
|
|
if (peerKeyInfo.KeyType == PAIRWISEKEY)
|
|
PeerPairMsg3Action(pAd, pEntry,
|
|
Elem);
|
|
else
|
|
PeerGroupMsg1Action(pAd, pEntry,
|
|
Elem);
|
|
}
|
|
} else {
|
|
/* The frame is snet by Supplicant. */
|
|
/* So the Authenticator side shall handle this. */
|
|
if ((peerKeyInfo.Request == 0) &&
|
|
(peerKeyInfo.Error == 0) &&
|
|
(peerKeyInfo.KeyMic == 1)) {
|
|
if (peerKeyInfo.Secure == 0
|
|
&& peerKeyInfo.KeyType ==
|
|
PAIRWISEKEY) {
|
|
/* EAPOL-Key(0,1,0,0,P,0,0,SNonce,MIC,Data) */
|
|
/* Process 1. message 2 of 4-way HS in WPA or WPA2 */
|
|
/* 2. message 4 of 4-way HS in WPA */
|
|
if (CONV_ARRARY_TO_u16
|
|
(pEapol_packet->KeyDesc.
|
|
KeyDataLen) == 0) {
|
|
PeerPairMsg4Action(pAd,
|
|
pEntry,
|
|
Elem);
|
|
} else {
|
|
PeerPairMsg2Action(pAd,
|
|
pEntry,
|
|
Elem);
|
|
}
|
|
} else if (peerKeyInfo.Secure == 1
|
|
&& peerKeyInfo.KeyType ==
|
|
PAIRWISEKEY) {
|
|
/* EAPOL-Key(1,1,0,0,P,0,0,0,MIC,0) */
|
|
/* Process message 4 of 4-way HS in WPA2 */
|
|
PeerPairMsg4Action(pAd, pEntry,
|
|
Elem);
|
|
} else if (peerKeyInfo.Secure == 1
|
|
&& peerKeyInfo.KeyType ==
|
|
GROUPKEY) {
|
|
/* EAPOL-Key(1,1,0,0,G,0,0,0,MIC,0) */
|
|
/* Process message 2 of Group key HS in WPA or WPA2 */
|
|
PeerGroupMsg2Action(pAd, pEntry,
|
|
&Elem->
|
|
Msg
|
|
[LENGTH_802_11],
|
|
(Elem->
|
|
MsgLen -
|
|
LENGTH_802_11));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
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
|
|
void * Pointer to outgoing Ndis frame
|
|
NumberOfFrag Number of fragment required
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
void RTMPToWirelessSta(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry,
|
|
u8 *pHeader802_3,
|
|
u32 HdrLen,
|
|
u8 *pData, u32 DataLen, IN BOOLEAN bClearFrame)
|
|
{
|
|
void *pPacket;
|
|
int Status;
|
|
|
|
if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
|
|
return;
|
|
|
|
do {
|
|
/* build a NDIS packet */
|
|
Status =
|
|
RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen,
|
|
pData, DataLen);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
break;
|
|
|
|
if (bClearFrame)
|
|
RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1);
|
|
else
|
|
RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0);
|
|
{
|
|
RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS);
|
|
|
|
RTMP_SET_PACKET_NET_DEVICE_MBSSID(pPacket, MAIN_MBSSID); /* set a default value */
|
|
if (pEntry->apidx != 0)
|
|
RTMP_SET_PACKET_NET_DEVICE_MBSSID(pPacket,
|
|
pEntry->
|
|
apidx);
|
|
|
|
RTMP_SET_PACKET_WCID(pPacket, (u8)pEntry->Aid);
|
|
RTMP_SET_PACKET_MOREDATA(pPacket, FALSE);
|
|
}
|
|
|
|
{
|
|
/* send out the packet */
|
|
Status = STASendPacket(pAd, pPacket);
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
u8 Index;
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
This is a function to initilize 4-way handshake
|
|
|
|
Return:
|
|
|
|
==========================================================================
|
|
*/
|
|
void WPAStart4WayHS(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry, unsigned long TimeInterval)
|
|
{
|
|
u8 Header802_3[14];
|
|
struct rt_eapol_packet EAPOLPKT;
|
|
u8 *pBssid = NULL;
|
|
u8 group_cipher = Ndis802_11WEPDisabled;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> WPAStart4WayHS\n"));
|
|
|
|
if (RTMP_TEST_FLAG
|
|
(pAd,
|
|
fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("[ERROR]WPAStart4WayHS : The interface is closed...\n"));
|
|
return;
|
|
}
|
|
|
|
if (pBssid == NULL) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("[ERROR]WPAStart4WayHS : No corresponding Authenticator.\n"));
|
|
return;
|
|
}
|
|
/* Check the status */
|
|
if ((pEntry->WpaState > AS_PTKSTART) || (pEntry->WpaState < AS_INITPMK)) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("[ERROR]WPAStart4WayHS : Not expect calling\n"));
|
|
return;
|
|
}
|
|
|
|
/* Increment replay counter by 1 */
|
|
ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
|
|
|
|
/* Randomly generate ANonce */
|
|
GenRandom(pAd, (u8 *) pBssid, pEntry->ANonce);
|
|
|
|
/* Construct EAPoL message - Pairwise Msg 1 */
|
|
/* EAPOL-Key(0,0,1,0,P,0,0,ANonce,0,DataKD_M1) */
|
|
NdisZeroMemory(&EAPOLPKT, sizeof(struct rt_eapol_packet));
|
|
ConstructEapolMsg(pEntry, group_cipher, EAPOL_PAIR_MSG_1, 0, /* Default key index */
|
|
pEntry->ANonce, NULL, /* TxRSC */
|
|
NULL, /* GTK */
|
|
NULL, /* RSNIE */
|
|
0, /* RSNIE length */
|
|
&EAPOLPKT);
|
|
|
|
/* Make outgoing frame */
|
|
MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
|
|
RTMPToWirelessSta(pAd, pEntry, Header802_3,
|
|
LENGTH_802_3, (u8 *)& EAPOLPKT,
|
|
CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4,
|
|
(pEntry->PortSecured ==
|
|
WPA_802_1X_PORT_SECURED) ? FALSE : TRUE);
|
|
|
|
/* Trigger Retry Timer */
|
|
RTMPModTimer(&pEntry->RetryTimer, TimeInterval);
|
|
|
|
/* Update State */
|
|
pEntry->WpaState = AS_PTKSTART;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("<=== WPAStart4WayHS: send Msg1 of 4-way \n"));
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Process Pairwise key Msg-1 of 4-way handshaking and send Msg-2
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
Elem Message body
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
void PeerPairMsg1Action(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
u8 PTK[80];
|
|
u8 Header802_3[14];
|
|
struct rt_eapol_packet * pMsg1;
|
|
u32 MsgLen;
|
|
struct rt_eapol_packet EAPOLPKT;
|
|
u8 *pCurrentAddr = NULL;
|
|
u8 *pmk_ptr = NULL;
|
|
u8 group_cipher = Ndis802_11WEPDisabled;
|
|
u8 *rsnie_ptr = NULL;
|
|
u8 rsnie_len = 0;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg1Action \n"));
|
|
|
|
if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
|
|
return;
|
|
|
|
if (Elem->MsgLen <
|
|
(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
|
|
sizeof(struct rt_key_descripter) - MAX_LEN_OF_RSNIE - 2))
|
|
return;
|
|
|
|
{
|
|
pCurrentAddr = pAd->CurrentAddress;
|
|
pmk_ptr = pAd->StaCfg.PMK;
|
|
group_cipher = pAd->StaCfg.GroupCipher;
|
|
rsnie_ptr = pAd->StaCfg.RSN_IE;
|
|
rsnie_len = pAd->StaCfg.RSNIE_Len;
|
|
}
|
|
|
|
/* Store the received frame */
|
|
pMsg1 = (struct rt_eapol_packet *) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
|
|
MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
|
|
|
|
/* Sanity Check peer Pairwise message 1 - Replay Counter */
|
|
if (PeerWpaMessageSanity(pAd, pMsg1, MsgLen, EAPOL_PAIR_MSG_1, pEntry)
|
|
== FALSE)
|
|
return;
|
|
|
|
/* Store Replay counter, it will use to verify message 3 and construct message 2 */
|
|
NdisMoveMemory(pEntry->R_Counter, pMsg1->KeyDesc.ReplayCounter,
|
|
LEN_KEY_DESC_REPLAY);
|
|
|
|
/* Store ANonce */
|
|
NdisMoveMemory(pEntry->ANonce, pMsg1->KeyDesc.KeyNonce,
|
|
LEN_KEY_DESC_NONCE);
|
|
|
|
/* Generate random SNonce */
|
|
GenRandom(pAd, (u8 *) pCurrentAddr, pEntry->SNonce);
|
|
|
|
{
|
|
/* Calculate PTK(ANonce, SNonce) */
|
|
WpaDerivePTK(pAd,
|
|
pmk_ptr,
|
|
pEntry->ANonce,
|
|
pEntry->Addr,
|
|
pEntry->SNonce, pCurrentAddr, PTK, LEN_PTK);
|
|
|
|
/* Save key to PTK entry */
|
|
NdisMoveMemory(pEntry->PTK, PTK, LEN_PTK);
|
|
}
|
|
|
|
/* Update WpaState */
|
|
pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
|
|
|
|
/* Construct EAPoL message - Pairwise Msg 2 */
|
|
/* EAPOL-Key(0,1,0,0,P,0,0,SNonce,MIC,DataKD_M2) */
|
|
NdisZeroMemory(&EAPOLPKT, sizeof(struct rt_eapol_packet));
|
|
ConstructEapolMsg(pEntry, group_cipher, EAPOL_PAIR_MSG_2, 0, /* DefaultKeyIdx */
|
|
pEntry->SNonce, NULL, /* TxRsc */
|
|
NULL, /* GTK */
|
|
(u8 *) rsnie_ptr, rsnie_len, &EAPOLPKT);
|
|
|
|
/* Make outgoing frame */
|
|
MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
|
|
|
|
RTMPToWirelessSta(pAd, pEntry,
|
|
Header802_3, sizeof(Header802_3), (u8 *)& EAPOLPKT,
|
|
CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4, TRUE);
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("<=== PeerPairMsg1Action: send Msg2 of 4-way \n"));
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
When receiving the second packet of 4-way pairwisekey handshake.
|
|
Return:
|
|
==========================================================================
|
|
*/
|
|
void PeerPairMsg2Action(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
u8 PTK[80];
|
|
BOOLEAN Cancelled;
|
|
struct rt_header_802_11 * pHeader;
|
|
struct rt_eapol_packet EAPOLPKT;
|
|
struct rt_eapol_packet * pMsg2;
|
|
u32 MsgLen;
|
|
u8 Header802_3[LENGTH_802_3];
|
|
u8 TxTsc[6];
|
|
u8 *pBssid = NULL;
|
|
u8 *pmk_ptr = NULL;
|
|
u8 *gtk_ptr = NULL;
|
|
u8 default_key = 0;
|
|
u8 group_cipher = Ndis802_11WEPDisabled;
|
|
u8 *rsnie_ptr = NULL;
|
|
u8 rsnie_len = 0;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg2Action \n"));
|
|
|
|
if ((!pEntry) || (!pEntry->ValidAsCLI))
|
|
return;
|
|
|
|
if (Elem->MsgLen <
|
|
(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
|
|
sizeof(struct rt_key_descripter) - MAX_LEN_OF_RSNIE - 2))
|
|
return;
|
|
|
|
/* check Entry in valid State */
|
|
if (pEntry->WpaState < AS_PTKSTART)
|
|
return;
|
|
|
|
/* pointer to 802.11 header */
|
|
pHeader = (struct rt_header_802_11 *) Elem->Msg;
|
|
|
|
/* skip 802.11_header(24-byte) and LLC_header(8) */
|
|
pMsg2 = (struct rt_eapol_packet *) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
|
|
MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
|
|
|
|
/* Store SNonce */
|
|
NdisMoveMemory(pEntry->SNonce, pMsg2->KeyDesc.KeyNonce,
|
|
LEN_KEY_DESC_NONCE);
|
|
|
|
{
|
|
/* Derive PTK */
|
|
WpaDerivePTK(pAd, (u8 *) pmk_ptr, pEntry->ANonce, /* ANONCE */
|
|
(u8 *) pBssid, pEntry->SNonce, /* SNONCE */
|
|
pEntry->Addr, PTK, LEN_PTK);
|
|
|
|
NdisMoveMemory(pEntry->PTK, PTK, LEN_PTK);
|
|
}
|
|
|
|
/* Sanity Check peer Pairwise message 2 - Replay Counter, MIC, RSNIE */
|
|
if (PeerWpaMessageSanity(pAd, pMsg2, MsgLen, EAPOL_PAIR_MSG_2, pEntry)
|
|
== FALSE)
|
|
return;
|
|
|
|
do {
|
|
/* delete retry timer */
|
|
RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
|
|
|
|
/* Change state */
|
|
pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
|
|
|
|
/* Increment replay counter by 1 */
|
|
ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
|
|
|
|
/* Construct EAPoL message - Pairwise Msg 3 */
|
|
NdisZeroMemory(&EAPOLPKT, sizeof(struct rt_eapol_packet));
|
|
ConstructEapolMsg(pEntry,
|
|
group_cipher,
|
|
EAPOL_PAIR_MSG_3,
|
|
default_key,
|
|
pEntry->ANonce,
|
|
TxTsc,
|
|
(u8 *) gtk_ptr,
|
|
(u8 *) rsnie_ptr, rsnie_len, &EAPOLPKT);
|
|
|
|
/* Make outgoing frame */
|
|
MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
|
|
RTMPToWirelessSta(pAd, pEntry, Header802_3, LENGTH_802_3,
|
|
(u8 *)& EAPOLPKT,
|
|
CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4,
|
|
(pEntry->PortSecured ==
|
|
WPA_802_1X_PORT_SECURED) ? FALSE : TRUE);
|
|
|
|
pEntry->ReTryCounter = PEER_MSG3_RETRY_TIMER_CTR;
|
|
RTMPSetTimer(&pEntry->RetryTimer, PEER_MSG3_RETRY_EXEC_INTV);
|
|
|
|
/* Update State */
|
|
pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
|
|
} while (FALSE);
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("<=== PeerPairMsg2Action: send Msg3 of 4-way \n"));
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Process Pairwise key Msg 3 of 4-way handshaking and send Msg 4
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
Elem Message body
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
void PeerPairMsg3Action(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
struct rt_header_802_11 * pHeader;
|
|
u8 Header802_3[14];
|
|
struct rt_eapol_packet EAPOLPKT;
|
|
struct rt_eapol_packet * pMsg3;
|
|
u32 MsgLen;
|
|
u8 *pCurrentAddr = NULL;
|
|
u8 group_cipher = Ndis802_11WEPDisabled;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg3Action \n"));
|
|
|
|
if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
|
|
return;
|
|
|
|
if (Elem->MsgLen <
|
|
(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
|
|
sizeof(struct rt_key_descripter) - MAX_LEN_OF_RSNIE - 2))
|
|
return;
|
|
|
|
{
|
|
pCurrentAddr = pAd->CurrentAddress;
|
|
group_cipher = pAd->StaCfg.GroupCipher;
|
|
|
|
}
|
|
|
|
/* Record 802.11 header & the received EAPOL packet Msg3 */
|
|
pHeader = (struct rt_header_802_11 *) Elem->Msg;
|
|
pMsg3 = (struct rt_eapol_packet *) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
|
|
MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
|
|
|
|
/* Sanity Check peer Pairwise message 3 - Replay Counter, MIC, RSNIE */
|
|
if (PeerWpaMessageSanity(pAd, pMsg3, MsgLen, EAPOL_PAIR_MSG_3, pEntry)
|
|
== FALSE)
|
|
return;
|
|
|
|
/* Save Replay counter, it will use construct message 4 */
|
|
NdisMoveMemory(pEntry->R_Counter, pMsg3->KeyDesc.ReplayCounter,
|
|
LEN_KEY_DESC_REPLAY);
|
|
|
|
/* Double check ANonce */
|
|
if (!NdisEqualMemory
|
|
(pEntry->ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) {
|
|
return;
|
|
}
|
|
/* Construct EAPoL message - Pairwise Msg 4 */
|
|
NdisZeroMemory(&EAPOLPKT, sizeof(struct rt_eapol_packet));
|
|
ConstructEapolMsg(pEntry, group_cipher, EAPOL_PAIR_MSG_4, 0, /* group key index not used in message 4 */
|
|
NULL, /* Nonce not used in message 4 */
|
|
NULL, /* TxRSC not used in message 4 */
|
|
NULL, /* GTK not used in message 4 */
|
|
NULL, /* RSN IE not used in message 4 */
|
|
0, &EAPOLPKT);
|
|
|
|
/* Update WpaState */
|
|
pEntry->WpaState = AS_PTKINITDONE;
|
|
|
|
/* Update pairwise key */
|
|
{
|
|
struct rt_cipher_key *pSharedKey;
|
|
|
|
pSharedKey = &pAd->SharedKey[BSS0][0];
|
|
|
|
NdisMoveMemory(pAd->StaCfg.PTK, pEntry->PTK, LEN_PTK);
|
|
|
|
/* Prepare pair-wise key information into shared key table */
|
|
NdisZeroMemory(pSharedKey, sizeof(struct rt_cipher_key));
|
|
pSharedKey->KeyLen = LEN_TKIP_EK;
|
|
NdisMoveMemory(pSharedKey->Key, &pAd->StaCfg.PTK[32],
|
|
LEN_TKIP_EK);
|
|
NdisMoveMemory(pSharedKey->RxMic, &pAd->StaCfg.PTK[48],
|
|
LEN_TKIP_RXMICK);
|
|
NdisMoveMemory(pSharedKey->TxMic,
|
|
&pAd->StaCfg.PTK[48 + LEN_TKIP_RXMICK],
|
|
LEN_TKIP_TXMICK);
|
|
|
|
/* Decide its ChiperAlg */
|
|
if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled)
|
|
pSharedKey->CipherAlg = CIPHER_TKIP;
|
|
else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled)
|
|
pSharedKey->CipherAlg = CIPHER_AES;
|
|
else
|
|
pSharedKey->CipherAlg = CIPHER_NONE;
|
|
|
|
/* Update these related information to struct rt_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 = pSharedKey->CipherAlg;
|
|
|
|
/* Update pairwise key information to ASIC Shared Key Table */
|
|
AsicAddSharedKeyEntry(pAd,
|
|
BSS0,
|
|
0,
|
|
pSharedKey->CipherAlg,
|
|
pSharedKey->Key,
|
|
pSharedKey->TxMic, pSharedKey->RxMic);
|
|
|
|
/* Update ASIC WCID attribute table and IVEIV table */
|
|
RTMPAddWcidAttributeEntry(pAd,
|
|
BSS0,
|
|
0, pSharedKey->CipherAlg, pEntry);
|
|
|
|
}
|
|
|
|
/* open 802.1x port control and privacy filter */
|
|
if (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK ||
|
|
pEntry->AuthMode == Ndis802_11AuthModeWPA2) {
|
|
pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
|
|
pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
|
|
|
|
STA_PORT_SECURED(pAd);
|
|
/* Indicate Connected for GUI */
|
|
pAd->IndicateMediaState = NdisMediaStateConnected;
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("PeerPairMsg3Action: AuthMode(%s) PairwiseCipher(%s) GroupCipher(%s) \n",
|
|
GetAuthMode(pEntry->AuthMode),
|
|
GetEncryptType(pEntry->WepStatus),
|
|
GetEncryptType(group_cipher)));
|
|
} else {
|
|
}
|
|
|
|
/* Init 802.3 header and send out */
|
|
MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
|
|
RTMPToWirelessSta(pAd, pEntry,
|
|
Header802_3, sizeof(Header802_3),
|
|
(u8 *)& EAPOLPKT,
|
|
CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4, TRUE);
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("<=== PeerPairMsg3Action: send Msg4 of 4-way \n"));
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
When receiving the last packet of 4-way pairwisekey handshake.
|
|
Initilize 2-way groupkey handshake following.
|
|
Return:
|
|
==========================================================================
|
|
*/
|
|
void PeerPairMsg4Action(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
struct rt_eapol_packet * pMsg4;
|
|
struct rt_header_802_11 * pHeader;
|
|
u32 MsgLen;
|
|
BOOLEAN Cancelled;
|
|
u8 group_cipher = Ndis802_11WEPDisabled;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg4Action\n"));
|
|
|
|
do {
|
|
if ((!pEntry) || (!pEntry->ValidAsCLI))
|
|
break;
|
|
|
|
if (Elem->MsgLen <
|
|
(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
|
|
sizeof(struct rt_key_descripter) - MAX_LEN_OF_RSNIE - 2))
|
|
break;
|
|
|
|
if (pEntry->WpaState < AS_PTKINIT_NEGOTIATING)
|
|
break;
|
|
|
|
/* pointer to 802.11 header */
|
|
pHeader = (struct rt_header_802_11 *) Elem->Msg;
|
|
|
|
/* skip 802.11_header(24-byte) and LLC_header(8) */
|
|
pMsg4 =
|
|
(struct rt_eapol_packet *) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
|
|
MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
|
|
|
|
/* Sanity Check peer Pairwise message 4 - Replay Counter, MIC */
|
|
if (PeerWpaMessageSanity
|
|
(pAd, pMsg4, MsgLen, EAPOL_PAIR_MSG_4, pEntry) == FALSE)
|
|
break;
|
|
|
|
/* 3. uses the MLME.SETKEYS.request to configure PTK into MAC */
|
|
NdisZeroMemory(&pEntry->PairwiseKey, sizeof(struct rt_cipher_key));
|
|
|
|
/* reset IVEIV in Asic */
|
|
AsicUpdateWCIDIVEIV(pAd, pEntry->Aid, 1, 0);
|
|
|
|
pEntry->PairwiseKey.KeyLen = LEN_TKIP_EK;
|
|
NdisMoveMemory(pEntry->PairwiseKey.Key, &pEntry->PTK[32],
|
|
LEN_TKIP_EK);
|
|
NdisMoveMemory(pEntry->PairwiseKey.RxMic,
|
|
&pEntry->PTK[TKIP_AP_RXMICK_OFFSET],
|
|
LEN_TKIP_RXMICK);
|
|
NdisMoveMemory(pEntry->PairwiseKey.TxMic,
|
|
&pEntry->PTK[TKIP_AP_TXMICK_OFFSET],
|
|
LEN_TKIP_TXMICK);
|
|
|
|
/* Set pairwise key to Asic */
|
|
{
|
|
pEntry->PairwiseKey.CipherAlg = CIPHER_NONE;
|
|
if (pEntry->WepStatus == Ndis802_11Encryption2Enabled)
|
|
pEntry->PairwiseKey.CipherAlg = CIPHER_TKIP;
|
|
else if (pEntry->WepStatus ==
|
|
Ndis802_11Encryption3Enabled)
|
|
pEntry->PairwiseKey.CipherAlg = CIPHER_AES;
|
|
|
|
/* Add Pair-wise key to Asic */
|
|
AsicAddPairwiseKeyEntry(pAd,
|
|
pEntry->Addr,
|
|
(u8)pEntry->Aid,
|
|
&pEntry->PairwiseKey);
|
|
|
|
/* update WCID attribute table and IVEIV table for this entry */
|
|
RTMPAddWcidAttributeEntry(pAd,
|
|
pEntry->apidx,
|
|
0,
|
|
pEntry->PairwiseKey.CipherAlg,
|
|
pEntry);
|
|
}
|
|
|
|
/* 4. upgrade state */
|
|
pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
|
|
pEntry->WpaState = AS_PTKINITDONE;
|
|
pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
|
|
|
|
if (pEntry->AuthMode == Ndis802_11AuthModeWPA2 ||
|
|
pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) {
|
|
pEntry->GTKState = REKEY_ESTABLISHED;
|
|
RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
|
|
|
|
/* send wireless event - for set key done WPA2 */
|
|
if (pAd->CommonCfg.bWirelessEvent)
|
|
RTMPSendWirelessEvent(pAd,
|
|
IW_SET_KEY_DONE_WPA2_EVENT_FLAG,
|
|
pEntry->Addr,
|
|
pEntry->apidx, 0);
|
|
|
|
DBGPRINT(RT_DEBUG_OFF,
|
|
("AP SETKEYS DONE - WPA2, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
|
|
pEntry->AuthMode,
|
|
GetAuthMode(pEntry->AuthMode),
|
|
pEntry->WepStatus,
|
|
GetEncryptType(pEntry->WepStatus),
|
|
group_cipher, GetEncryptType(group_cipher)));
|
|
} else {
|
|
/* 5. init Group 2-way handshake if necessary. */
|
|
WPAStart2WayGroupHS(pAd, pEntry);
|
|
|
|
pEntry->ReTryCounter = GROUP_MSG1_RETRY_TIMER_CTR;
|
|
RTMPModTimer(&pEntry->RetryTimer,
|
|
PEER_MSG3_RETRY_EXEC_INTV);
|
|
}
|
|
} while (FALSE);
|
|
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
This is a function to send the first packet of 2-way groupkey handshake
|
|
Return:
|
|
|
|
==========================================================================
|
|
*/
|
|
void WPAStart2WayGroupHS(struct rt_rtmp_adapter *pAd, struct rt_mac_table_entry *pEntry)
|
|
{
|
|
u8 Header802_3[14];
|
|
u8 TxTsc[6];
|
|
struct rt_eapol_packet EAPOLPKT;
|
|
u8 group_cipher = Ndis802_11WEPDisabled;
|
|
u8 default_key = 0;
|
|
u8 *gnonce_ptr = NULL;
|
|
u8 *gtk_ptr = NULL;
|
|
u8 *pBssid = NULL;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> WPAStart2WayGroupHS\n"));
|
|
|
|
if ((!pEntry) || (!pEntry->ValidAsCLI))
|
|
return;
|
|
|
|
do {
|
|
/* Increment replay counter by 1 */
|
|
ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
|
|
|
|
/* Construct EAPoL message - Group Msg 1 */
|
|
NdisZeroMemory(&EAPOLPKT, sizeof(struct rt_eapol_packet));
|
|
ConstructEapolMsg(pEntry,
|
|
group_cipher,
|
|
EAPOL_GROUP_MSG_1,
|
|
default_key,
|
|
(u8 *) gnonce_ptr,
|
|
TxTsc, (u8 *) gtk_ptr, NULL, 0, &EAPOLPKT);
|
|
|
|
/* Make outgoing frame */
|
|
MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
|
|
RTMPToWirelessSta(pAd, pEntry,
|
|
Header802_3, LENGTH_802_3,
|
|
(u8 *)& EAPOLPKT,
|
|
CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4,
|
|
FALSE);
|
|
|
|
} while (FALSE);
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("<=== WPAStart2WayGroupHS : send out Group Message 1 \n"));
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Process Group key 2-way handshaking
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
Elem Message body
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
void PeerGroupMsg1Action(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
|
|
{
|
|
u8 Header802_3[14];
|
|
struct rt_eapol_packet EAPOLPKT;
|
|
struct rt_eapol_packet * pGroup;
|
|
u32 MsgLen;
|
|
BOOLEAN Cancelled;
|
|
u8 default_key = 0;
|
|
u8 group_cipher = Ndis802_11WEPDisabled;
|
|
u8 *pCurrentAddr = NULL;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> PeerGroupMsg1Action \n"));
|
|
|
|
if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
|
|
return;
|
|
|
|
{
|
|
pCurrentAddr = pAd->CurrentAddress;
|
|
group_cipher = pAd->StaCfg.GroupCipher;
|
|
default_key = pAd->StaCfg.DefaultKeyId;
|
|
}
|
|
|
|
/* Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8) */
|
|
pGroup = (struct rt_eapol_packet *) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
|
|
MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
|
|
|
|
/* Sanity Check peer group message 1 - Replay Counter, MIC, RSNIE */
|
|
if (PeerWpaMessageSanity(pAd, pGroup, MsgLen, EAPOL_GROUP_MSG_1, pEntry)
|
|
== FALSE)
|
|
return;
|
|
|
|
/* delete retry timer */
|
|
RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
|
|
|
|
/* Save Replay counter, it will use to construct message 2 */
|
|
NdisMoveMemory(pEntry->R_Counter, pGroup->KeyDesc.ReplayCounter,
|
|
LEN_KEY_DESC_REPLAY);
|
|
|
|
/* Construct EAPoL message - Group Msg 2 */
|
|
NdisZeroMemory(&EAPOLPKT, sizeof(struct rt_eapol_packet));
|
|
ConstructEapolMsg(pEntry, group_cipher, EAPOL_GROUP_MSG_2, default_key, NULL, /* Nonce not used */
|
|
NULL, /* TxRSC not used */
|
|
NULL, /* GTK not used */
|
|
NULL, /* RSN IE not used */
|
|
0, &EAPOLPKT);
|
|
|
|
/* open 802.1x port control and privacy filter */
|
|
pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
|
|
pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
|
|
|
|
STA_PORT_SECURED(pAd);
|
|
/* Indicate Connected for GUI */
|
|
pAd->IndicateMediaState = NdisMediaStateConnected;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("PeerGroupMsg1Action: AuthMode(%s) PairwiseCipher(%s) GroupCipher(%s) \n",
|
|
GetAuthMode(pEntry->AuthMode),
|
|
GetEncryptType(pEntry->WepStatus),
|
|
GetEncryptType(group_cipher)));
|
|
|
|
/* init header and Fill Packet and send Msg 2 to authenticator */
|
|
MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
|
|
RTMPToWirelessSta(pAd, pEntry,
|
|
Header802_3, sizeof(Header802_3),
|
|
(u8 *)& EAPOLPKT,
|
|
CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4, FALSE);
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("<=== PeerGroupMsg1Action: sned group message 2\n"));
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
When receiving the last packet of 2-way groupkey handshake.
|
|
Return:
|
|
==========================================================================
|
|
*/
|
|
void PeerGroupMsg2Action(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry,
|
|
void * Msg, u32 MsgLen)
|
|
{
|
|
u32 Len;
|
|
u8 *pData;
|
|
BOOLEAN Cancelled;
|
|
struct rt_eapol_packet * pMsg2;
|
|
u8 group_cipher = Ndis802_11WEPDisabled;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> PeerGroupMsg2Action \n"));
|
|
|
|
do {
|
|
if ((!pEntry) || (!pEntry->ValidAsCLI))
|
|
break;
|
|
|
|
if (MsgLen <
|
|
(LENGTH_802_1_H + LENGTH_EAPOL_H + sizeof(struct rt_key_descripter) -
|
|
MAX_LEN_OF_RSNIE - 2))
|
|
break;
|
|
|
|
if (pEntry->WpaState != AS_PTKINITDONE)
|
|
break;
|
|
|
|
pData = (u8 *)Msg;
|
|
pMsg2 = (struct rt_eapol_packet *) (pData + LENGTH_802_1_H);
|
|
Len = MsgLen - LENGTH_802_1_H;
|
|
|
|
/* Sanity Check peer group message 2 - Replay Counter, MIC */
|
|
if (PeerWpaMessageSanity
|
|
(pAd, pMsg2, Len, EAPOL_GROUP_MSG_2, pEntry) == FALSE)
|
|
break;
|
|
|
|
/* 3. upgrade state */
|
|
|
|
RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
|
|
pEntry->GTKState = REKEY_ESTABLISHED;
|
|
|
|
if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2)
|
|
|| (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) {
|
|
/* send wireless event - for set key done WPA2 */
|
|
if (pAd->CommonCfg.bWirelessEvent)
|
|
RTMPSendWirelessEvent(pAd,
|
|
IW_SET_KEY_DONE_WPA2_EVENT_FLAG,
|
|
pEntry->Addr,
|
|
pEntry->apidx, 0);
|
|
|
|
DBGPRINT(RT_DEBUG_OFF,
|
|
("AP SETKEYS DONE - WPA2, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
|
|
pEntry->AuthMode,
|
|
GetAuthMode(pEntry->AuthMode),
|
|
pEntry->WepStatus,
|
|
GetEncryptType(pEntry->WepStatus),
|
|
group_cipher, GetEncryptType(group_cipher)));
|
|
} else {
|
|
/* send wireless event - for set key done WPA */
|
|
if (pAd->CommonCfg.bWirelessEvent)
|
|
RTMPSendWirelessEvent(pAd,
|
|
IW_SET_KEY_DONE_WPA1_EVENT_FLAG,
|
|
pEntry->Addr,
|
|
pEntry->apidx, 0);
|
|
|
|
DBGPRINT(RT_DEBUG_OFF,
|
|
("AP SETKEYS DONE - WPA1, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
|
|
pEntry->AuthMode,
|
|
GetAuthMode(pEntry->AuthMode),
|
|
pEntry->WepStatus,
|
|
GetEncryptType(pEntry->WepStatus),
|
|
group_cipher, GetEncryptType(group_cipher)));
|
|
}
|
|
} while (FALSE);
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
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(u8 EAPType, 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;
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
The pseudo-random function(PRF) that hashes various inputs to
|
|
derive a pseudo-random value. To add liveness to the pseudo-random
|
|
value, a nonce should be one of the inputs.
|
|
|
|
It is used to generate PTK, GTK or some specific random value.
|
|
|
|
Arguments:
|
|
u8 *key, - the key material for HMAC_SHA1 use
|
|
int key_len - the length of key
|
|
u8 *prefix - a prefix label
|
|
int prefix_len - the length of the label
|
|
u8 *data - a specific data with variable length
|
|
int data_len - the length of a specific data
|
|
int len - the output lenght
|
|
|
|
Return Value:
|
|
u8 *output - the calculated result
|
|
|
|
Note:
|
|
802.11i-2004 Annex H.3
|
|
|
|
========================================================================
|
|
*/
|
|
void PRF(u8 * key,
|
|
int key_len,
|
|
u8 * prefix,
|
|
int prefix_len,
|
|
u8 * data, int data_len, u8 * output, int len)
|
|
{
|
|
int i;
|
|
u8 *input;
|
|
int currentindex = 0;
|
|
int total_len;
|
|
|
|
/* Allocate memory for input */
|
|
os_alloc_mem(NULL, (u8 **) & input, 1024);
|
|
|
|
if (input == NULL) {
|
|
DBGPRINT(RT_DEBUG_ERROR, ("PRF: no memory!\n"));
|
|
return;
|
|
}
|
|
/* Generate concatenation input */
|
|
NdisMoveMemory(input, prefix, prefix_len);
|
|
|
|
/* Concatenate a single octet containing 0 */
|
|
input[prefix_len] = 0;
|
|
|
|
/* Concatenate specific data */
|
|
NdisMoveMemory(&input[prefix_len + 1], data, data_len);
|
|
total_len = prefix_len + 1 + data_len;
|
|
|
|
/* Concatenate a single octet containing 0 */
|
|
/* This octet shall be update later */
|
|
input[total_len] = 0;
|
|
total_len++;
|
|
|
|
/* Iterate to calculate the result by hmac-sha-1 */
|
|
/* Then concatenate to last result */
|
|
for (i = 0; i < (len + 19) / 20; i++) {
|
|
HMAC_SHA1(key, key_len, input, total_len, &output[currentindex],
|
|
SHA1_DIGEST_SIZE);
|
|
currentindex += 20;
|
|
|
|
/* update the last octet */
|
|
input[total_len - 1]++;
|
|
}
|
|
os_free_mem(NULL, input);
|
|
}
|
|
|
|
/*
|
|
* F(P, S, c, i) = U1 xor U2 xor ... Uc
|
|
* U1 = PRF(P, S || Int(i))
|
|
* U2 = PRF(P, U1)
|
|
* Uc = PRF(P, Uc-1)
|
|
*/
|
|
|
|
static void F(char *password, unsigned char *ssid, int ssidlength,
|
|
int iterations, int count, unsigned char *output)
|
|
{
|
|
unsigned char digest[36], digest1[SHA1_DIGEST_SIZE];
|
|
int i, j;
|
|
|
|
/* U1 = PRF(P, S || int(i)) */
|
|
memcpy(digest, ssid, ssidlength);
|
|
digest[ssidlength] = (unsigned char)((count >> 24) & 0xff);
|
|
digest[ssidlength + 1] = (unsigned char)((count >> 16) & 0xff);
|
|
digest[ssidlength + 2] = (unsigned char)((count >> 8) & 0xff);
|
|
digest[ssidlength + 3] = (unsigned char)(count & 0xff);
|
|
HMAC_SHA1((unsigned char *)password, (int)strlen(password), digest, ssidlength + 4, digest1, SHA1_DIGEST_SIZE); /* for WPA update */
|
|
|
|
/* output = U1 */
|
|
memcpy(output, digest1, SHA1_DIGEST_SIZE);
|
|
|
|
for (i = 1; i < iterations; i++) {
|
|
/* Un = PRF(P, Un-1) */
|
|
HMAC_SHA1((unsigned char *)password, (int)strlen(password), digest1, SHA1_DIGEST_SIZE, digest, SHA1_DIGEST_SIZE); /* for WPA update */
|
|
memcpy(digest1, digest, SHA1_DIGEST_SIZE);
|
|
|
|
/* output = output xor Un */
|
|
for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
|
|
output[j] ^= digest[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* password - ascii string up to 63 characters in length
|
|
* ssid - octet string up to 32 octets
|
|
* ssidlength - length of ssid in octets
|
|
* output must be 40 octets in length and outputs 256 bits of key
|
|
*/
|
|
int PasswordHash(char *password, u8 *ssid, int ssidlength, u8 *output)
|
|
{
|
|
if ((strlen(password) > 63) || (ssidlength > 32))
|
|
return 0;
|
|
|
|
F(password, ssid, ssidlength, 4096, 1, output);
|
|
F(password, ssid, ssidlength, 4096, 2, &output[SHA1_DIGEST_SIZE]);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK.
|
|
It shall be called by 4-way handshake processing.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
PMK - pointer to PMK
|
|
ANonce - pointer to ANonce
|
|
AA - pointer to Authenticator Address
|
|
SNonce - pointer to SNonce
|
|
SA - pointer to Supplicant Address
|
|
len - indicate the length of PTK (octet)
|
|
|
|
Return Value:
|
|
Output pointer to the PTK
|
|
|
|
Note:
|
|
Refer to IEEE 802.11i-2004 8.5.1.2
|
|
|
|
========================================================================
|
|
*/
|
|
void WpaDerivePTK(struct rt_rtmp_adapter *pAd,
|
|
u8 * PMK,
|
|
u8 * ANonce,
|
|
u8 * AA,
|
|
u8 * SNonce,
|
|
u8 * SA, u8 * output, u32 len)
|
|
{
|
|
u8 concatenation[76];
|
|
u32 CurrPos = 0;
|
|
u8 temp[32];
|
|
u8 Prefix[] =
|
|
{ 'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ',
|
|
'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'
|
|
};
|
|
|
|
/* initiate the concatenation input */
|
|
NdisZeroMemory(temp, sizeof(temp));
|
|
NdisZeroMemory(concatenation, 76);
|
|
|
|
/* Get smaller address */
|
|
if (RTMPCompareMemory(SA, AA, 6) == 1)
|
|
NdisMoveMemory(concatenation, AA, 6);
|
|
else
|
|
NdisMoveMemory(concatenation, SA, 6);
|
|
CurrPos += 6;
|
|
|
|
/* Get larger address */
|
|
if (RTMPCompareMemory(SA, AA, 6) == 1)
|
|
NdisMoveMemory(&concatenation[CurrPos], SA, 6);
|
|
else
|
|
NdisMoveMemory(&concatenation[CurrPos], AA, 6);
|
|
|
|
/* store the larger mac address for backward compatible of */
|
|
/* ralink proprietary STA-key issue */
|
|
NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN);
|
|
CurrPos += 6;
|
|
|
|
/* Get smaller Nonce */
|
|
if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
|
|
NdisMoveMemory(&concatenation[CurrPos], temp, 32); /* patch for ralink proprietary STA-key issue */
|
|
else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
|
|
NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
|
|
else
|
|
NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
|
|
CurrPos += 32;
|
|
|
|
/* Get larger Nonce */
|
|
if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
|
|
NdisMoveMemory(&concatenation[CurrPos], temp, 32); /* patch for ralink proprietary STA-key issue */
|
|
else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
|
|
NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
|
|
else
|
|
NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
|
|
CurrPos += 32;
|
|
|
|
hex_dump("concatenation=", concatenation, 76);
|
|
|
|
/* Use PRF to generate PTK */
|
|
PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len);
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Generate random number by software.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
macAddr - pointer to local MAC address
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
802.1ii-2004 Annex H.5
|
|
|
|
========================================================================
|
|
*/
|
|
void GenRandom(struct rt_rtmp_adapter *pAd, u8 * macAddr, u8 * random)
|
|
{
|
|
int i, curr;
|
|
u8 local[80], KeyCounter[32];
|
|
u8 result[80];
|
|
unsigned long CurrentTime;
|
|
u8 prefix[] =
|
|
{ 'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r' };
|
|
|
|
/* Zero the related information */
|
|
NdisZeroMemory(result, 80);
|
|
NdisZeroMemory(local, 80);
|
|
NdisZeroMemory(KeyCounter, 32);
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
/* copy the local MAC address */
|
|
COPY_MAC_ADDR(local, macAddr);
|
|
curr = MAC_ADDR_LEN;
|
|
|
|
/* concatenate the current time */
|
|
NdisGetSystemUpTime(&CurrentTime);
|
|
NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime));
|
|
curr += sizeof(CurrentTime);
|
|
|
|
/* concatenate the last result */
|
|
NdisMoveMemory(&local[curr], result, 32);
|
|
curr += 32;
|
|
|
|
/* concatenate a variable */
|
|
NdisMoveMemory(&local[curr], &i, 2);
|
|
curr += 2;
|
|
|
|
/* calculate the result */
|
|
PRF(KeyCounter, 32, prefix, 12, local, curr, result, 32);
|
|
}
|
|
|
|
NdisMoveMemory(random, result, 32);
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Build cipher suite in RSN-IE.
|
|
It only shall be called by RTMPMakeRSNIE.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
ElementID - indicate the WPA1 or WPA2
|
|
WepStatus - indicate the encryption type
|
|
bMixCipher - a boolean to indicate the pairwise cipher and group
|
|
cipher are the same or not
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
static void RTMPMakeRsnIeCipher(struct rt_rtmp_adapter *pAd,
|
|
u8 ElementID,
|
|
u32 WepStatus,
|
|
IN BOOLEAN bMixCipher,
|
|
u8 FlexibleCipher,
|
|
u8 *pRsnIe, u8 * rsn_len)
|
|
{
|
|
u8 PairwiseCnt;
|
|
|
|
*rsn_len = 0;
|
|
|
|
/* decide WPA2 or WPA1 */
|
|
if (ElementID == Wpa2Ie) {
|
|
struct rt_rsnie2 *pRsnie_cipher = (struct rt_rsnie2 *)pRsnIe;
|
|
|
|
/* Assign the verson as 1 */
|
|
pRsnie_cipher->version = 1;
|
|
|
|
switch (WepStatus) {
|
|
/* TKIP mode */
|
|
case Ndis802_11Encryption2Enabled:
|
|
NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
|
|
pRsnie_cipher->ucount = 1;
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
|
|
OUI_WPA2_TKIP, 4);
|
|
*rsn_len = sizeof(struct rt_rsnie2);
|
|
break;
|
|
|
|
/* AES mode */
|
|
case Ndis802_11Encryption3Enabled:
|
|
if (bMixCipher)
|
|
NdisMoveMemory(pRsnie_cipher->mcast,
|
|
OUI_WPA2_TKIP, 4);
|
|
else
|
|
NdisMoveMemory(pRsnie_cipher->mcast,
|
|
OUI_WPA2_CCMP, 4);
|
|
pRsnie_cipher->ucount = 1;
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
|
|
OUI_WPA2_CCMP, 4);
|
|
*rsn_len = sizeof(struct rt_rsnie2);
|
|
break;
|
|
|
|
/* TKIP-AES mix mode */
|
|
case Ndis802_11Encryption4Enabled:
|
|
NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
|
|
|
|
PairwiseCnt = 1;
|
|
/* Insert WPA2 TKIP as the first pairwise cipher */
|
|
if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) {
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
|
|
OUI_WPA2_TKIP, 4);
|
|
/* Insert WPA2 AES as the secondary pairwise cipher */
|
|
if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) {
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].
|
|
oui + 4, OUI_WPA2_CCMP,
|
|
4);
|
|
PairwiseCnt = 2;
|
|
}
|
|
} else {
|
|
/* Insert WPA2 AES as the first pairwise cipher */
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
|
|
OUI_WPA2_CCMP, 4);
|
|
}
|
|
|
|
pRsnie_cipher->ucount = PairwiseCnt;
|
|
*rsn_len = sizeof(struct rt_rsnie2) + (4 * (PairwiseCnt - 1));
|
|
break;
|
|
}
|
|
|
|
if ((pAd->OpMode == OPMODE_STA) &&
|
|
(pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) &&
|
|
(pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) {
|
|
u32 GroupCipher = pAd->StaCfg.GroupCipher;
|
|
switch (GroupCipher) {
|
|
case Ndis802_11GroupWEP40Enabled:
|
|
NdisMoveMemory(pRsnie_cipher->mcast,
|
|
OUI_WPA2_WEP40, 4);
|
|
break;
|
|
case Ndis802_11GroupWEP104Enabled:
|
|
NdisMoveMemory(pRsnie_cipher->mcast,
|
|
OUI_WPA2_WEP104, 4);
|
|
break;
|
|
}
|
|
}
|
|
/* swap for big-endian platform */
|
|
pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
|
|
pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
|
|
} else {
|
|
struct rt_rsnie *pRsnie_cipher = (struct rt_rsnie *)pRsnIe;
|
|
|
|
/* Assign OUI and version */
|
|
NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4);
|
|
pRsnie_cipher->version = 1;
|
|
|
|
switch (WepStatus) {
|
|
/* TKIP mode */
|
|
case Ndis802_11Encryption2Enabled:
|
|
NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
|
|
pRsnie_cipher->ucount = 1;
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
|
|
OUI_WPA_TKIP, 4);
|
|
*rsn_len = sizeof(struct rt_rsnie);
|
|
break;
|
|
|
|
/* AES mode */
|
|
case Ndis802_11Encryption3Enabled:
|
|
if (bMixCipher)
|
|
NdisMoveMemory(pRsnie_cipher->mcast,
|
|
OUI_WPA_TKIP, 4);
|
|
else
|
|
NdisMoveMemory(pRsnie_cipher->mcast,
|
|
OUI_WPA_CCMP, 4);
|
|
pRsnie_cipher->ucount = 1;
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
|
|
OUI_WPA_CCMP, 4);
|
|
*rsn_len = sizeof(struct rt_rsnie);
|
|
break;
|
|
|
|
/* TKIP-AES mix mode */
|
|
case Ndis802_11Encryption4Enabled:
|
|
NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
|
|
|
|
PairwiseCnt = 1;
|
|
/* Insert WPA TKIP as the first pairwise cipher */
|
|
if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) {
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
|
|
OUI_WPA_TKIP, 4);
|
|
/* Insert WPA AES as the secondary pairwise cipher */
|
|
if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) {
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].
|
|
oui + 4, OUI_WPA_CCMP,
|
|
4);
|
|
PairwiseCnt = 2;
|
|
}
|
|
} else {
|
|
/* Insert WPA AES as the first pairwise cipher */
|
|
NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
|
|
OUI_WPA_CCMP, 4);
|
|
}
|
|
|
|
pRsnie_cipher->ucount = PairwiseCnt;
|
|
*rsn_len = sizeof(struct rt_rsnie) + (4 * (PairwiseCnt - 1));
|
|
break;
|
|
}
|
|
|
|
if ((pAd->OpMode == OPMODE_STA) &&
|
|
(pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) &&
|
|
(pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) {
|
|
u32 GroupCipher = pAd->StaCfg.GroupCipher;
|
|
switch (GroupCipher) {
|
|
case Ndis802_11GroupWEP40Enabled:
|
|
NdisMoveMemory(pRsnie_cipher->mcast,
|
|
OUI_WPA_WEP40, 4);
|
|
break;
|
|
case Ndis802_11GroupWEP104Enabled:
|
|
NdisMoveMemory(pRsnie_cipher->mcast,
|
|
OUI_WPA_WEP104, 4);
|
|
break;
|
|
}
|
|
}
|
|
/* swap for big-endian platform */
|
|
pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
|
|
pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Build AKM suite in RSN-IE.
|
|
It only shall be called by RTMPMakeRSNIE.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
ElementID - indicate the WPA1 or WPA2
|
|
AuthMode - indicate the authentication mode
|
|
apidx - indicate the interface index
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
static void RTMPMakeRsnIeAKM(struct rt_rtmp_adapter *pAd,
|
|
u8 ElementID,
|
|
u32 AuthMode,
|
|
u8 apidx,
|
|
u8 *pRsnIe, u8 * rsn_len)
|
|
{
|
|
struct rt_rsnie_auth *pRsnie_auth;
|
|
u8 AkmCnt = 1; /* default as 1 */
|
|
|
|
pRsnie_auth = (struct rt_rsnie_auth *) (pRsnIe + (*rsn_len));
|
|
|
|
/* decide WPA2 or WPA1 */
|
|
if (ElementID == Wpa2Ie) {
|
|
|
|
switch (AuthMode) {
|
|
case Ndis802_11AuthModeWPA2:
|
|
case Ndis802_11AuthModeWPA1WPA2:
|
|
NdisMoveMemory(pRsnie_auth->auth[0].oui,
|
|
OUI_WPA2_8021X_AKM, 4);
|
|
break;
|
|
|
|
case Ndis802_11AuthModeWPA2PSK:
|
|
case Ndis802_11AuthModeWPA1PSKWPA2PSK:
|
|
NdisMoveMemory(pRsnie_auth->auth[0].oui,
|
|
OUI_WPA2_PSK_AKM, 4);
|
|
break;
|
|
default:
|
|
AkmCnt = 0;
|
|
break;
|
|
|
|
}
|
|
} else {
|
|
switch (AuthMode) {
|
|
case Ndis802_11AuthModeWPA:
|
|
case Ndis802_11AuthModeWPA1WPA2:
|
|
NdisMoveMemory(pRsnie_auth->auth[0].oui,
|
|
OUI_WPA_8021X_AKM, 4);
|
|
break;
|
|
|
|
case Ndis802_11AuthModeWPAPSK:
|
|
case Ndis802_11AuthModeWPA1PSKWPA2PSK:
|
|
NdisMoveMemory(pRsnie_auth->auth[0].oui,
|
|
OUI_WPA_PSK_AKM, 4);
|
|
break;
|
|
|
|
case Ndis802_11AuthModeWPANone:
|
|
NdisMoveMemory(pRsnie_auth->auth[0].oui,
|
|
OUI_WPA_NONE_AKM, 4);
|
|
break;
|
|
default:
|
|
AkmCnt = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pRsnie_auth->acount = AkmCnt;
|
|
pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount);
|
|
|
|
/* update current RSNIE length */
|
|
(*rsn_len) += (sizeof(struct rt_rsnie_auth) + (4 * (AkmCnt - 1)));
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Build capability in RSN-IE.
|
|
It only shall be called by RTMPMakeRSNIE.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
ElementID - indicate the WPA1 or WPA2
|
|
apidx - indicate the interface index
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
static void RTMPMakeRsnIeCap(struct rt_rtmp_adapter *pAd,
|
|
u8 ElementID,
|
|
u8 apidx,
|
|
u8 *pRsnIe, u8 * rsn_len)
|
|
{
|
|
RSN_CAPABILITIES *pRSN_Cap;
|
|
|
|
/* it could be ignored in WPA1 mode */
|
|
if (ElementID == WpaIe)
|
|
return;
|
|
|
|
pRSN_Cap = (RSN_CAPABILITIES *) (pRsnIe + (*rsn_len));
|
|
|
|
pRSN_Cap->word = cpu2le16(pRSN_Cap->word);
|
|
|
|
(*rsn_len) += sizeof(RSN_CAPABILITIES); /* update current RSNIE length */
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Build RSN IE context. It is not included element-ID and length.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
AuthMode - indicate the authentication mode
|
|
WepStatus - indicate the encryption type
|
|
apidx - indicate the interface index
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
void RTMPMakeRSNIE(struct rt_rtmp_adapter *pAd,
|
|
u32 AuthMode, u32 WepStatus, u8 apidx)
|
|
{
|
|
u8 *pRsnIe = NULL; /* primary RSNIE */
|
|
u8 *rsnielen_cur_p = 0; /* the length of the primary RSNIE */
|
|
u8 *rsnielen_ex_cur_p = 0; /* the length of the secondary RSNIE */
|
|
u8 PrimaryRsnie;
|
|
BOOLEAN bMixCipher = FALSE; /* indicate the pairwise and group cipher are different */
|
|
u8 p_offset;
|
|
WPA_MIX_PAIR_CIPHER FlexibleCipher = WPA_TKIPAES_WPA2_TKIPAES; /* it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode */
|
|
|
|
rsnielen_cur_p = NULL;
|
|
rsnielen_ex_cur_p = NULL;
|
|
|
|
{
|
|
{
|
|
if (pAd->StaCfg.WpaSupplicantUP !=
|
|
WPA_SUPPLICANT_DISABLE) {
|
|
if (AuthMode < Ndis802_11AuthModeWPA)
|
|
return;
|
|
} else {
|
|
/* Support WPAPSK or WPA2PSK in STA-Infra mode */
|
|
/* Support WPANone in STA-Adhoc mode */
|
|
if ((AuthMode != Ndis802_11AuthModeWPAPSK) &&
|
|
(AuthMode != Ndis802_11AuthModeWPA2PSK) &&
|
|
(AuthMode != Ndis802_11AuthModeWPANone)
|
|
)
|
|
return;
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPMakeRSNIE(STA)\n"));
|
|
|
|
/* Zero RSNIE context */
|
|
pAd->StaCfg.RSNIE_Len = 0;
|
|
NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE);
|
|
|
|
/* Pointer to RSNIE */
|
|
rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len;
|
|
pRsnIe = pAd->StaCfg.RSN_IE;
|
|
|
|
bMixCipher = pAd->StaCfg.bMixCipher;
|
|
}
|
|
}
|
|
|
|
/* indicate primary RSNIE as WPA or WPA2 */
|
|
if ((AuthMode == Ndis802_11AuthModeWPA) ||
|
|
(AuthMode == Ndis802_11AuthModeWPAPSK) ||
|
|
(AuthMode == Ndis802_11AuthModeWPANone) ||
|
|
(AuthMode == Ndis802_11AuthModeWPA1WPA2) ||
|
|
(AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK))
|
|
PrimaryRsnie = WpaIe;
|
|
else
|
|
PrimaryRsnie = Wpa2Ie;
|
|
|
|
{
|
|
/* Build the primary RSNIE */
|
|
/* 1. insert cipher suite */
|
|
RTMPMakeRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher,
|
|
FlexibleCipher, pRsnIe, &p_offset);
|
|
|
|
/* 2. insert AKM */
|
|
RTMPMakeRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe,
|
|
&p_offset);
|
|
|
|
/* 3. insert capability */
|
|
RTMPMakeRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset);
|
|
}
|
|
|
|
/* 4. update the RSNIE length */
|
|
*rsnielen_cur_p = p_offset;
|
|
|
|
hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p));
|
|
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Check whether the received frame is EAP frame.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
pEntry - pointer to active entry
|
|
pData - the received frame
|
|
DataByteCount - the received frame's length
|
|
FromWhichBSSID - indicate the interface index
|
|
|
|
Return:
|
|
TRUE - This frame is EAP frame
|
|
FALSE - otherwise
|
|
==========================================================================
|
|
*/
|
|
BOOLEAN RTMPCheckWPAframe(struct rt_rtmp_adapter *pAd,
|
|
struct rt_mac_table_entry *pEntry,
|
|
u8 *pData,
|
|
unsigned long DataByteCount, u8 FromWhichBSSID)
|
|
{
|
|
unsigned long Body_len;
|
|
BOOLEAN Cancelled;
|
|
|
|
if (DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H))
|
|
return FALSE;
|
|
|
|
/* Skip LLC header */
|
|
if (NdisEqualMemory(SNAP_802_1H, pData, 6) ||
|
|
/* Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL */
|
|
NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6)) {
|
|
pData += 6;
|
|
}
|
|
/* Skip 2-bytes EAPoL type */
|
|
if (NdisEqualMemory(EAPOL, pData, 2)) {
|
|
pData += 2;
|
|
} else
|
|
return FALSE;
|
|
|
|
switch (*(pData + 1)) {
|
|
case EAPPacket:
|
|
Body_len = (*(pData + 2) << 8) | (*(pData + 3));
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n",
|
|
Body_len));
|
|
break;
|
|
case EAPOLStart:
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("Receive EAPOL-Start frame, TYPE = 1 \n"));
|
|
if (pEntry->EnqueueEapolStartTimerRunning !=
|
|
EAPOL_START_DISABLE) {
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("Cancel the EnqueueEapolStartTimerRunning \n"));
|
|
RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer,
|
|
&Cancelled);
|
|
pEntry->EnqueueEapolStartTimerRunning =
|
|
EAPOL_START_DISABLE;
|
|
}
|
|
break;
|
|
case EAPOLLogoff:
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("Receive EAPOLLogoff frame, TYPE = 2 \n"));
|
|
break;
|
|
case EAPOLKey:
|
|
Body_len = (*(pData + 2) << 8) | (*(pData + 3));
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n",
|
|
Body_len));
|
|
break;
|
|
case EAPOLASFAlert:
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("Receive EAPOLASFAlert frame, TYPE = 4 \n"));
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Report the EAP message type
|
|
|
|
Arguments:
|
|
msg - EAPOL_PAIR_MSG_1
|
|
EAPOL_PAIR_MSG_2
|
|
EAPOL_PAIR_MSG_3
|
|
EAPOL_PAIR_MSG_4
|
|
EAPOL_GROUP_MSG_1
|
|
EAPOL_GROUP_MSG_2
|
|
|
|
Return:
|
|
message type string
|
|
|
|
==========================================================================
|
|
*/
|
|
char *GetEapolMsgType(char msg)
|
|
{
|
|
if (msg == EAPOL_PAIR_MSG_1)
|
|
return "Pairwise Message 1";
|
|
else if (msg == EAPOL_PAIR_MSG_2)
|
|
return "Pairwise Message 2";
|
|
else if (msg == EAPOL_PAIR_MSG_3)
|
|
return "Pairwise Message 3";
|
|
else if (msg == EAPOL_PAIR_MSG_4)
|
|
return "Pairwise Message 4";
|
|
else if (msg == EAPOL_GROUP_MSG_1)
|
|
return "Group Message 1";
|
|
else if (msg == EAPOL_GROUP_MSG_2)
|
|
return "Group Message 2";
|
|
else
|
|
return "Invalid Message";
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Check Sanity RSN IE of EAPoL message
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
========================================================================
|
|
*/
|
|
BOOLEAN RTMPCheckRSNIE(struct rt_rtmp_adapter *pAd,
|
|
u8 *pData,
|
|
u8 DataLen,
|
|
struct rt_mac_table_entry *pEntry, u8 * Offset)
|
|
{
|
|
u8 *pVIE;
|
|
u8 len;
|
|
struct rt_eid * pEid;
|
|
BOOLEAN result = FALSE;
|
|
|
|
pVIE = pData;
|
|
len = DataLen;
|
|
*Offset = 0;
|
|
|
|
while (len > sizeof(struct rt_rsnie2)) {
|
|
pEid = (struct rt_eid *) pVIE;
|
|
/* WPA RSN IE */
|
|
if ((pEid->Eid == IE_WPA)
|
|
&& (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) {
|
|
if ((pEntry->AuthMode == Ndis802_11AuthModeWPA
|
|
|| pEntry->AuthMode == Ndis802_11AuthModeWPAPSK)
|
|
&&
|
|
(NdisEqualMemory
|
|
(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len))
|
|
&& (pEntry->RSNIE_Len == (pEid->Len + 2))) {
|
|
result = TRUE;
|
|
}
|
|
|
|
*Offset += (pEid->Len + 2);
|
|
}
|
|
/* WPA2 RSN IE */
|
|
else if ((pEid->Eid == IE_RSN)
|
|
&& (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) {
|
|
if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2
|
|
|| pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)
|
|
&& (pEid->Eid == pEntry->RSN_IE[0])
|
|
&& ((pEid->Len + 2) >= pEntry->RSNIE_Len)
|
|
&&
|
|
(NdisEqualMemory
|
|
(pEid->Octet, &pEntry->RSN_IE[2],
|
|
pEntry->RSNIE_Len - 2))) {
|
|
|
|
result = TRUE;
|
|
}
|
|
|
|
*Offset += (pEid->Len + 2);
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
pVIE += (pEid->Len + 2);
|
|
len -= (pEid->Len + 2);
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK.
|
|
GTK is encaptulated in KDE format at p.83 802.11i D10
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
802.11i D10
|
|
|
|
========================================================================
|
|
*/
|
|
BOOLEAN RTMPParseEapolKeyData(struct rt_rtmp_adapter *pAd,
|
|
u8 *pKeyData,
|
|
u8 KeyDataLen,
|
|
u8 GroupKeyIndex,
|
|
u8 MsgType,
|
|
IN BOOLEAN bWPA2, struct rt_mac_table_entry *pEntry)
|
|
{
|
|
struct rt_kde_encap * pKDE = NULL;
|
|
u8 *pMyKeyData = pKeyData;
|
|
u8 KeyDataLength = KeyDataLen;
|
|
u8 GTKLEN = 0;
|
|
u8 DefaultIdx = 0;
|
|
u8 skip_offset;
|
|
|
|
/* Verify The RSN IE contained in pairewise_msg_2 && pairewise_msg_3 and skip it */
|
|
if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_3) {
|
|
/* Check RSN IE whether it is WPA2/WPA2PSK */
|
|
if (!RTMPCheckRSNIE
|
|
(pAd, pKeyData, KeyDataLen, pEntry, &skip_offset)) {
|
|
/* send wireless event - for RSN IE different */
|
|
if (pAd->CommonCfg.bWirelessEvent)
|
|
RTMPSendWirelessEvent(pAd,
|
|
IW_RSNIE_DIFF_EVENT_FLAG,
|
|
pEntry->Addr,
|
|
pEntry->apidx, 0);
|
|
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("RSN_IE Different in msg %d of 4-way handshake!\n",
|
|
MsgType));
|
|
hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen);
|
|
hex_dump("Desired RSN_IE ", pEntry->RSN_IE,
|
|
pEntry->RSNIE_Len);
|
|
|
|
return FALSE;
|
|
} else {
|
|
if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3) {
|
|
WpaShowAllsuite(pMyKeyData, skip_offset);
|
|
|
|
/* skip RSN IE */
|
|
pMyKeyData += skip_offset;
|
|
KeyDataLength -= skip_offset;
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("RTMPParseEapolKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n",
|
|
skip_offset));
|
|
} else
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n",
|
|
KeyDataLength));
|
|
/*hex_dump("remain data", pMyKeyData, KeyDataLength); */
|
|
|
|
/* Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2 */
|
|
if (bWPA2
|
|
&& (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1)) {
|
|
if (KeyDataLength >= 8) /* KDE format exclude GTK length */
|
|
{
|
|
pKDE = (struct rt_kde_encap *) pMyKeyData;
|
|
|
|
DefaultIdx = pKDE->GTKEncap.Kid;
|
|
|
|
/* Sanity check - KED length */
|
|
if (KeyDataLength < (pKDE->Len + 2)) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("ERROR: The len from KDE is too short \n"));
|
|
return FALSE;
|
|
}
|
|
/* Get GTK length - refer to IEEE 802.11i-2004 p.82 */
|
|
GTKLEN = pKDE->Len - 6;
|
|
if (GTKLEN < LEN_AES_KEY) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("ERROR: GTK Key length is too short (%d) \n",
|
|
GTKLEN));
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("ERROR: KDE format length is too short \n"));
|
|
return FALSE;
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n",
|
|
DefaultIdx, GTKLEN));
|
|
/* skip it */
|
|
pMyKeyData += 8;
|
|
KeyDataLength -= 8;
|
|
|
|
} else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1) {
|
|
DefaultIdx = GroupKeyIndex;
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("GTK DefaultKeyID=%d \n", DefaultIdx));
|
|
}
|
|
/* Sanity check - shared key index must be 1 ~ 3 */
|
|
if (DefaultIdx < 1 || DefaultIdx > 3) {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("ERROR: GTK Key index(%d) is invalid in %s %s \n",
|
|
DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"),
|
|
GetEapolMsgType(MsgType)));
|
|
return FALSE;
|
|
}
|
|
|
|
{
|
|
struct rt_cipher_key *pSharedKey;
|
|
|
|
/* set key material, TxMic and RxMic */
|
|
NdisMoveMemory(pAd->StaCfg.GTK, pMyKeyData, 32);
|
|
pAd->StaCfg.DefaultKeyId = DefaultIdx;
|
|
|
|
pSharedKey = &pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId];
|
|
|
|
/* Prepare pair-wise key information into shared key table */
|
|
NdisZeroMemory(pSharedKey, sizeof(struct rt_cipher_key));
|
|
pSharedKey->KeyLen = LEN_TKIP_EK;
|
|
NdisMoveMemory(pSharedKey->Key, pAd->StaCfg.GTK, LEN_TKIP_EK);
|
|
NdisMoveMemory(pSharedKey->RxMic, &pAd->StaCfg.GTK[16],
|
|
LEN_TKIP_RXMICK);
|
|
NdisMoveMemory(pSharedKey->TxMic, &pAd->StaCfg.GTK[24],
|
|
LEN_TKIP_TXMICK);
|
|
|
|
/* Update Shared Key CipherAlg */
|
|
pSharedKey->CipherAlg = CIPHER_NONE;
|
|
if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled)
|
|
pSharedKey->CipherAlg = CIPHER_TKIP;
|
|
else if (pAd->StaCfg.GroupCipher ==
|
|
Ndis802_11Encryption3Enabled)
|
|
pSharedKey->CipherAlg = CIPHER_AES;
|
|
else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled)
|
|
pSharedKey->CipherAlg = CIPHER_WEP64;
|
|
else if (pAd->StaCfg.GroupCipher ==
|
|
Ndis802_11GroupWEP104Enabled)
|
|
pSharedKey->CipherAlg = CIPHER_WEP128;
|
|
|
|
/* Update group key information to ASIC Shared Key Table */
|
|
AsicAddSharedKeyEntry(pAd,
|
|
BSS0,
|
|
pAd->StaCfg.DefaultKeyId,
|
|
pSharedKey->CipherAlg,
|
|
pSharedKey->Key,
|
|
pSharedKey->TxMic, pSharedKey->RxMic);
|
|
|
|
/* Update ASIC WCID attribute table and IVEIV table */
|
|
RTMPAddWcidAttributeEntry(pAd,
|
|
BSS0,
|
|
pAd->StaCfg.DefaultKeyId,
|
|
pSharedKey->CipherAlg, NULL);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Construct EAPoL message for WPA handshaking
|
|
Its format is below,
|
|
|
|
+--------------------+
|
|
| Protocol Version | 1 octet
|
|
+--------------------+
|
|
| Protocol Type | 1 octet
|
|
+--------------------+
|
|
| Body Length | 2 octets
|
|
+--------------------+
|
|
| Descriptor Type | 1 octet
|
|
+--------------------+
|
|
| Key Information | 2 octets
|
|
+--------------------+
|
|
| Key Length | 1 octet
|
|
+--------------------+
|
|
| Key Repaly Counter | 8 octets
|
|
+--------------------+
|
|
| Key Nonce | 32 octets
|
|
+--------------------+
|
|
| Key IV | 16 octets
|
|
+--------------------+
|
|
| Key RSC | 8 octets
|
|
+--------------------+
|
|
| Key ID or Reserved | 8 octets
|
|
+--------------------+
|
|
| Key MIC | 16 octets
|
|
+--------------------+
|
|
| Key Data Length | 2 octets
|
|
+--------------------+
|
|
| Key Data | n octets
|
|
+--------------------+
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
void ConstructEapolMsg(struct rt_mac_table_entry *pEntry,
|
|
u8 GroupKeyWepStatus,
|
|
u8 MsgType,
|
|
u8 DefaultKeyIdx,
|
|
u8 * KeyNonce,
|
|
u8 * TxRSC,
|
|
u8 * GTK,
|
|
u8 * RSNIE,
|
|
u8 RSNIE_Len, struct rt_eapol_packet * pMsg)
|
|
{
|
|
BOOLEAN bWPA2 = FALSE;
|
|
u8 KeyDescVer;
|
|
|
|
/* Choose WPA2 or not */
|
|
if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) ||
|
|
(pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
|
|
bWPA2 = TRUE;
|
|
|
|
/* Init Packet and Fill header */
|
|
pMsg->ProVer = EAPOL_VER;
|
|
pMsg->ProType = EAPOLKey;
|
|
|
|
/* Default 95 bytes, the EAPoL-Key descriptor exclude Key-data field */
|
|
SET_u16_TO_ARRARY(pMsg->Body_Len, LEN_EAPOL_KEY_MSG);
|
|
|
|
/* Fill in EAPoL descriptor */
|
|
if (bWPA2)
|
|
pMsg->KeyDesc.Type = WPA2_KEY_DESC;
|
|
else
|
|
pMsg->KeyDesc.Type = WPA1_KEY_DESC;
|
|
|
|
/* Key Descriptor Version (bits 0-2) specifies the key descriptor version type */
|
|
{
|
|
/* Fill in Key information, refer to IEEE Std 802.11i-2004 page 78 */
|
|
/* When either the pairwise or the group cipher is AES, the DESC_TYPE_AES(2) shall be used. */
|
|
KeyDescVer =
|
|
(((pEntry->WepStatus == Ndis802_11Encryption3Enabled)
|
|
|| (GroupKeyWepStatus ==
|
|
Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES)
|
|
: (DESC_TYPE_TKIP));
|
|
}
|
|
|
|
pMsg->KeyDesc.KeyInfo.KeyDescVer = KeyDescVer;
|
|
|
|
/* Specify Key Type as Group(0) or Pairwise(1) */
|
|
if (MsgType >= EAPOL_GROUP_MSG_1)
|
|
pMsg->KeyDesc.KeyInfo.KeyType = GROUPKEY;
|
|
else
|
|
pMsg->KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
|
|
|
|
/* Specify Key Index, only group_msg1_WPA1 */
|
|
if (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))
|
|
pMsg->KeyDesc.KeyInfo.KeyIndex = DefaultKeyIdx;
|
|
|
|
if (MsgType == EAPOL_PAIR_MSG_3)
|
|
pMsg->KeyDesc.KeyInfo.Install = 1;
|
|
|
|
if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3)
|
|
|| (MsgType == EAPOL_GROUP_MSG_1))
|
|
pMsg->KeyDesc.KeyInfo.KeyAck = 1;
|
|
|
|
if (MsgType != EAPOL_PAIR_MSG_1)
|
|
pMsg->KeyDesc.KeyInfo.KeyMic = 1;
|
|
|
|
if ((bWPA2 && (MsgType >= EAPOL_PAIR_MSG_3)) ||
|
|
(!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))) {
|
|
pMsg->KeyDesc.KeyInfo.Secure = 1;
|
|
}
|
|
|
|
if (bWPA2 && ((MsgType == EAPOL_PAIR_MSG_3) ||
|
|
(MsgType == EAPOL_GROUP_MSG_1))) {
|
|
pMsg->KeyDesc.KeyInfo.EKD_DL = 1;
|
|
}
|
|
/* key Information element has done. */
|
|
*(u16 *) (&pMsg->KeyDesc.KeyInfo) =
|
|
cpu2le16(*(u16 *) (&pMsg->KeyDesc.KeyInfo));
|
|
|
|
/* Fill in Key Length */
|
|
{
|
|
if (MsgType >= EAPOL_GROUP_MSG_1) {
|
|
/* the length of group key cipher */
|
|
pMsg->KeyDesc.KeyLength[1] =
|
|
((GroupKeyWepStatus ==
|
|
Ndis802_11Encryption2Enabled) ? TKIP_GTK_LENGTH :
|
|
LEN_AES_KEY);
|
|
} else {
|
|
/* the length of pairwise key cipher */
|
|
pMsg->KeyDesc.KeyLength[1] =
|
|
((pEntry->WepStatus ==
|
|
Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY :
|
|
LEN_AES_KEY);
|
|
}
|
|
}
|
|
|
|
/* Fill in replay counter */
|
|
NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter,
|
|
LEN_KEY_DESC_REPLAY);
|
|
|
|
/* Fill Key Nonce field */
|
|
/* ANonce : pairwise_msg1 & pairwise_msg3 */
|
|
/* SNonce : pairwise_msg2 */
|
|
/* GNonce : group_msg1_wpa1 */
|
|
if ((MsgType <= EAPOL_PAIR_MSG_3)
|
|
|| ((!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1))))
|
|
NdisMoveMemory(pMsg->KeyDesc.KeyNonce, KeyNonce,
|
|
LEN_KEY_DESC_NONCE);
|
|
|
|
/* Fill key IV - WPA2 as 0, WPA1 as random */
|
|
if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) {
|
|
/* Suggest IV be random number plus some number, */
|
|
NdisMoveMemory(pMsg->KeyDesc.KeyIv, &KeyNonce[16],
|
|
LEN_KEY_DESC_IV);
|
|
pMsg->KeyDesc.KeyIv[15] += 2;
|
|
}
|
|
/* Fill Key RSC field */
|
|
/* It contains the RSC for the GTK being installed. */
|
|
if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2)
|
|
|| (MsgType == EAPOL_GROUP_MSG_1)) {
|
|
NdisMoveMemory(pMsg->KeyDesc.KeyRsc, TxRSC, 6);
|
|
}
|
|
/* Clear Key MIC field for MIC calculation later */
|
|
NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
|
|
|
|
ConstructEapolKeyData(pEntry,
|
|
GroupKeyWepStatus,
|
|
KeyDescVer,
|
|
MsgType,
|
|
DefaultKeyIdx, GTK, RSNIE, RSNIE_Len, pMsg);
|
|
|
|
/* Calculate MIC and fill in KeyMic Field except Pairwise Msg 1. */
|
|
if (MsgType != EAPOL_PAIR_MSG_1) {
|
|
CalculateMIC(KeyDescVer, pEntry->PTK, pMsg);
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("===> ConstructEapolMsg for %s %s\n",
|
|
((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType)));
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
(" Body length = %d \n",
|
|
CONV_ARRARY_TO_u16(pMsg->Body_Len)));
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
(" Key length = %d \n",
|
|
CONV_ARRARY_TO_u16(pMsg->KeyDesc.KeyLength)));
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Construct the Key Data field of EAPoL message
|
|
|
|
Arguments:
|
|
pAd Pointer to our adapter
|
|
Elem Message body
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
void ConstructEapolKeyData(struct rt_mac_table_entry *pEntry,
|
|
u8 GroupKeyWepStatus,
|
|
u8 keyDescVer,
|
|
u8 MsgType,
|
|
u8 DefaultKeyIdx,
|
|
u8 * GTK,
|
|
u8 * RSNIE,
|
|
u8 RSNIE_LEN, struct rt_eapol_packet * pMsg)
|
|
{
|
|
u8 *mpool, *Key_Data, *Rc4GTK;
|
|
u8 ekey[(LEN_KEY_DESC_IV + LEN_EAP_EK)];
|
|
unsigned long data_offset;
|
|
BOOLEAN bWPA2Capable = FALSE;
|
|
struct rt_rtmp_adapter *pAd = pEntry->pAd;
|
|
BOOLEAN GTK_Included = FALSE;
|
|
|
|
/* Choose WPA2 or not */
|
|
if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) ||
|
|
(pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
|
|
bWPA2Capable = TRUE;
|
|
|
|
if (MsgType == EAPOL_PAIR_MSG_1 ||
|
|
MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2)
|
|
return;
|
|
|
|
/* allocate memory pool */
|
|
os_alloc_mem(NULL, (u8 **) & mpool, 1500);
|
|
|
|
if (mpool == NULL)
|
|
return;
|
|
|
|
/* Rc4GTK Len = 512 */
|
|
Rc4GTK = (u8 *) ROUND_UP(mpool, 4);
|
|
/* Key_Data Len = 512 */
|
|
Key_Data = (u8 *) ROUND_UP(Rc4GTK + 512, 4);
|
|
|
|
NdisZeroMemory(Key_Data, 512);
|
|
SET_u16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, 0);
|
|
data_offset = 0;
|
|
|
|
/* Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3 */
|
|
if (RSNIE_LEN
|
|
&& ((MsgType == EAPOL_PAIR_MSG_2)
|
|
|| (MsgType == EAPOL_PAIR_MSG_3))) {
|
|
u8 *pmkid_ptr = NULL;
|
|
u8 pmkid_len = 0;
|
|
|
|
RTMPInsertRSNIE(&Key_Data[data_offset],
|
|
&data_offset,
|
|
RSNIE, RSNIE_LEN, pmkid_ptr, pmkid_len);
|
|
}
|
|
|
|
/* Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2 */
|
|
if (bWPA2Capable
|
|
&& ((MsgType == EAPOL_PAIR_MSG_3)
|
|
|| (MsgType == EAPOL_GROUP_MSG_1))) {
|
|
/* Key Data Encapsulation (KDE) format - 802.11i-2004 Figure-43w and Table-20h */
|
|
Key_Data[data_offset + 0] = 0xDD;
|
|
|
|
if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) {
|
|
Key_Data[data_offset + 1] = 0x16; /* 4+2+16(OUI+DataType+DataField) */
|
|
} else {
|
|
Key_Data[data_offset + 1] = 0x26; /* 4+2+32(OUI+DataType+DataField) */
|
|
}
|
|
|
|
Key_Data[data_offset + 2] = 0x00;
|
|
Key_Data[data_offset + 3] = 0x0F;
|
|
Key_Data[data_offset + 4] = 0xAC;
|
|
Key_Data[data_offset + 5] = 0x01;
|
|
|
|
/* GTK KDE format - 802.11i-2004 Figure-43x */
|
|
Key_Data[data_offset + 6] = (DefaultKeyIdx & 0x03);
|
|
Key_Data[data_offset + 7] = 0x00; /* Reserved Byte */
|
|
|
|
data_offset += 8;
|
|
}
|
|
|
|
/* Encapsulate GTK */
|
|
/* Only for pairwise_msg3_WPA2 and group_msg1 */
|
|
if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable)
|
|
|| (MsgType == EAPOL_GROUP_MSG_1)) {
|
|
/* Fill in GTK */
|
|
if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) {
|
|
NdisMoveMemory(&Key_Data[data_offset], GTK,
|
|
LEN_AES_KEY);
|
|
data_offset += LEN_AES_KEY;
|
|
} else {
|
|
NdisMoveMemory(&Key_Data[data_offset], GTK,
|
|
TKIP_GTK_LENGTH);
|
|
data_offset += TKIP_GTK_LENGTH;
|
|
}
|
|
|
|
GTK_Included = TRUE;
|
|
}
|
|
|
|
/* This whole key-data field shall be encrypted if a GTK is included. */
|
|
/* Encrypt the data material in key data field with KEK */
|
|
if (GTK_Included) {
|
|
/*hex_dump("GTK_Included", Key_Data, data_offset); */
|
|
|
|
if ((keyDescVer == DESC_TYPE_AES)) {
|
|
u8 remainder = 0;
|
|
u8 pad_len = 0;
|
|
|
|
/* Key Descriptor Version 2 or 3: AES key wrap, defined in IETF RFC 3394, */
|
|
/* shall be used to encrypt the Key Data field using the KEK field from */
|
|
/* the derived PTK. */
|
|
|
|
/* If the Key Data field uses the NIST AES key wrap, then the Key Data field */
|
|
/* shall be padded before encrypting if the key data length is less than 16 */
|
|
/* octets or if it is not a multiple of 8. The padding consists of appending */
|
|
/* a single octet 0xdd followed by zero or more 0x00 octets. */
|
|
if ((remainder = data_offset & 0x07) != 0) {
|
|
int i;
|
|
|
|
pad_len = (8 - remainder);
|
|
Key_Data[data_offset] = 0xDD;
|
|
for (i = 1; i < pad_len; i++)
|
|
Key_Data[data_offset + i] = 0;
|
|
|
|
data_offset += pad_len;
|
|
}
|
|
|
|
AES_GTK_KEY_WRAP(&pEntry->PTK[16], Key_Data,
|
|
data_offset, Rc4GTK);
|
|
/* AES wrap function will grow 8 bytes in length */
|
|
data_offset += 8;
|
|
} else {
|
|
/* Key Descriptor Version 1: ARC4 is used to encrypt the Key Data field
|
|
using the KEK field from the derived PTK. */
|
|
|
|
/* PREPARE Encrypted "Key DATA" field. (Encrypt GTK with RC4, usinf PTK[16]->[31] as Key, IV-field as IV) */
|
|
/* put TxTsc in Key RSC field */
|
|
pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; /*Init crc32. */
|
|
|
|
/* ekey is the contanetion of IV-field, and PTK[16]->PTK[31] */
|
|
NdisMoveMemory(ekey, pMsg->KeyDesc.KeyIv,
|
|
LEN_KEY_DESC_IV);
|
|
NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &pEntry->PTK[16],
|
|
LEN_EAP_EK);
|
|
ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, ekey, sizeof(ekey)); /*INIT SBOX, KEYLEN+3(IV) */
|
|
pAd->PrivateInfo.FCSCRC32 =
|
|
RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, Key_Data,
|
|
data_offset);
|
|
WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK,
|
|
Key_Data, data_offset);
|
|
}
|
|
|
|
NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset);
|
|
} else {
|
|
NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset);
|
|
}
|
|
|
|
/* Update key data length field and total body length */
|
|
SET_u16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, data_offset);
|
|
INC_u16_TO_ARRARY(pMsg->Body_Len, data_offset);
|
|
|
|
os_free_mem(NULL, mpool);
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Calcaulate MIC. It is used during 4-ways handsharking.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
PeerWepStatus - indicate the encryption type
|
|
|
|
Return Value:
|
|
|
|
Note:
|
|
|
|
========================================================================
|
|
*/
|
|
static void CalculateMIC(u8 KeyDescVer,
|
|
u8 * PTK, struct rt_eapol_packet * pMsg)
|
|
{
|
|
u8 *OutBuffer;
|
|
unsigned long FrameLen = 0;
|
|
u8 mic[LEN_KEY_DESC_MIC];
|
|
u8 digest[80];
|
|
|
|
/* allocate memory for MIC calculation */
|
|
os_alloc_mem(NULL, (u8 **) & OutBuffer, 512);
|
|
|
|
if (OutBuffer == NULL) {
|
|
DBGPRINT(RT_DEBUG_ERROR, ("CalculateMIC: no memory!\n"));
|
|
return;
|
|
}
|
|
/* make a frame for calculating MIC. */
|
|
MakeOutgoingFrame(OutBuffer, &FrameLen,
|
|
CONV_ARRARY_TO_u16(pMsg->Body_Len) + 4, pMsg,
|
|
END_OF_ARGS);
|
|
|
|
NdisZeroMemory(mic, sizeof(mic));
|
|
|
|
/* Calculate MIC */
|
|
if (KeyDescVer == DESC_TYPE_AES) {
|
|
HMAC_SHA1(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, digest,
|
|
SHA1_DIGEST_SIZE);
|
|
NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC);
|
|
} else {
|
|
HMAC_MD5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, mic,
|
|
MD5_DIGEST_SIZE);
|
|
}
|
|
|
|
/* store the calculated MIC */
|
|
NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC);
|
|
|
|
os_free_mem(NULL, OutBuffer);
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
Some received frames can't decrypt by Asic, so decrypt them by software.
|
|
|
|
Arguments:
|
|
pAd - pointer to our pAdapter context
|
|
PeerWepStatus - indicate the encryption type
|
|
|
|
Return Value:
|
|
NDIS_STATUS_SUCCESS - decryption successful
|
|
NDIS_STATUS_FAILURE - decryption failure
|
|
|
|
========================================================================
|
|
*/
|
|
int RTMPSoftDecryptBroadCastData(struct rt_rtmp_adapter *pAd,
|
|
struct rt_rx_blk *pRxBlk,
|
|
IN NDIS_802_11_ENCRYPTION_STATUS
|
|
GroupCipher, struct rt_cipher_key *pShard_key)
|
|
{
|
|
struct rt_rxwi * pRxWI = pRxBlk->pRxWI;
|
|
|
|
/* handle WEP decryption */
|
|
if (GroupCipher == Ndis802_11Encryption1Enabled) {
|
|
if (RTMPSoftDecryptWEP
|
|
(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount,
|
|
pShard_key)) {
|
|
|
|
/*Minus IV[4] & ICV[4] */
|
|
pRxWI->MPDUtotalByteCount -= 8;
|
|
} else {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("ERROR : Software decrypt WEP data fails.\n"));
|
|
/* give up this frame */
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
}
|
|
/* handle TKIP decryption */
|
|
else if (GroupCipher == Ndis802_11Encryption2Enabled) {
|
|
if (RTMPSoftDecryptTKIP
|
|
(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0,
|
|
pShard_key)) {
|
|
|
|
/*Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV */
|
|
pRxWI->MPDUtotalByteCount -= 20;
|
|
} else {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("ERROR : RTMPSoftDecryptTKIP Failed\n"));
|
|
/* give up this frame */
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
}
|
|
/* handle AES decryption */
|
|
else if (GroupCipher == Ndis802_11Encryption3Enabled) {
|
|
if (RTMPSoftDecryptAES
|
|
(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount,
|
|
pShard_key)) {
|
|
|
|
/*8 bytes MIC, 8 bytes IV/EIV (CCMP Header) */
|
|
pRxWI->MPDUtotalByteCount -= 16;
|
|
} else {
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("ERROR : RTMPSoftDecryptAES Failed\n"));
|
|
/* give up this frame */
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
} else {
|
|
/* give up this frame */
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
u8 *GetSuiteFromRSNIE(u8 *rsnie,
|
|
u32 rsnie_len, u8 type, u8 * count)
|
|
{
|
|
struct rt_eid * pEid;
|
|
int len;
|
|
u8 *pBuf;
|
|
int offset = 0;
|
|
struct rt_rsnie_auth *pAkm;
|
|
u16 acount;
|
|
BOOLEAN isWPA2 = FALSE;
|
|
|
|
pEid = (struct rt_eid *) rsnie;
|
|
len = rsnie_len - 2; /* exclude IE and length */
|
|
pBuf = (u8 *)& pEid->Octet[0];
|
|
|
|
/* set default value */
|
|
*count = 0;
|
|
|
|
/* Check length */
|
|
if ((len <= 0) || (pEid->Len != len)) {
|
|
DBGPRINT_ERR(("%s : The length is invalid\n", __func__));
|
|
return NULL;
|
|
}
|
|
/* Check WPA or WPA2 */
|
|
if (pEid->Eid == IE_WPA) {
|
|
struct rt_rsnie *pRsnie = (struct rt_rsnie *)pBuf;
|
|
u16 ucount;
|
|
|
|
if (len < sizeof(struct rt_rsnie)) {
|
|
DBGPRINT_ERR(("%s : The length is too short for WPA\n",
|
|
__func__));
|
|
return NULL;
|
|
}
|
|
/* Get the count of pairwise cipher */
|
|
ucount = cpu2le16(pRsnie->ucount);
|
|
if (ucount > 2) {
|
|
DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount));
|
|
return NULL;
|
|
}
|
|
/* Get the group cipher */
|
|
if (type == GROUP_SUITE) {
|
|
*count = 1;
|
|
return pRsnie->mcast;
|
|
}
|
|
/* Get the pairwise cipher suite */
|
|
else if (type == PAIRWISE_SUITE) {
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("%s : The count of pairwise cipher is %d\n",
|
|
__func__, ucount));
|
|
*count = ucount;
|
|
return pRsnie->ucast[0].oui;
|
|
}
|
|
|
|
offset = sizeof(struct rt_rsnie) + (4 * (ucount - 1));
|
|
|
|
} else if (pEid->Eid == IE_RSN) {
|
|
struct rt_rsnie2 *pRsnie = (struct rt_rsnie2 *)pBuf;
|
|
u16 ucount;
|
|
|
|
isWPA2 = TRUE;
|
|
|
|
if (len < sizeof(struct rt_rsnie2)) {
|
|
DBGPRINT_ERR(("%s : The length is too short for WPA2\n",
|
|
__func__));
|
|
return NULL;
|
|
}
|
|
/* Get the count of pairwise cipher */
|
|
ucount = cpu2le16(pRsnie->ucount);
|
|
if (ucount > 2) {
|
|
DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount));
|
|
return NULL;
|
|
}
|
|
/* Get the group cipher */
|
|
if (type == GROUP_SUITE) {
|
|
*count = 1;
|
|
return pRsnie->mcast;
|
|
}
|
|
/* Get the pairwise cipher suite */
|
|
else if (type == PAIRWISE_SUITE) {
|
|
DBGPRINT(RT_DEBUG_TRACE,
|
|
("%s : The count of pairwise cipher is %d\n",
|
|
__func__, ucount));
|
|
*count = ucount;
|
|
return pRsnie->ucast[0].oui;
|
|
}
|
|
|
|
offset = sizeof(struct rt_rsnie2) + (4 * (ucount - 1));
|
|
|
|
} else {
|
|
DBGPRINT_ERR(("%s : Unknown IE (%d)\n", __func__, pEid->Eid));
|
|
return NULL;
|
|
}
|
|
|
|
/* skip group cipher and pairwise cipher suite */
|
|
pBuf += offset;
|
|
len -= offset;
|
|
|
|
if (len < sizeof(struct rt_rsnie_auth)) {
|
|
DBGPRINT_ERR(("%s : The length of RSNIE is too short\n",
|
|
__func__));
|
|
return NULL;
|
|
}
|
|
/* pointer to AKM count */
|
|
pAkm = (struct rt_rsnie_auth *)pBuf;
|
|
|
|
/* Get the count of pairwise cipher */
|
|
acount = cpu2le16(pAkm->acount);
|
|
if (acount > 2) {
|
|
DBGPRINT_ERR(("%s : The count(%d) of AKM is invlaid\n",
|
|
__func__, acount));
|
|
return NULL;
|
|
}
|
|
/* Get the AKM suite */
|
|
if (type == AKM_SUITE) {
|
|
DBGPRINT(RT_DEBUG_TRACE, ("%s : The count of AKM is %d\n",
|
|
__func__, acount));
|
|
*count = acount;
|
|
return pAkm->auth[0].oui;
|
|
}
|
|
offset = sizeof(struct rt_rsnie_auth) + (4 * (acount - 1));
|
|
|
|
pBuf += offset;
|
|
len -= offset;
|
|
|
|
/* The remaining length must larger than (RSN-Capability(2) + PMKID-Count(2) + PMKID(16~)) */
|
|
if (len >= (sizeof(RSN_CAPABILITIES) + 2 + LEN_PMKID)) {
|
|
/* Skip RSN capability and PMKID-Count */
|
|
pBuf += (sizeof(RSN_CAPABILITIES) + 2);
|
|
len -= (sizeof(RSN_CAPABILITIES) + 2);
|
|
|
|
/* Get PMKID */
|
|
if (type == PMKID_LIST) {
|
|
*count = 1;
|
|
return pBuf;
|
|
}
|
|
} else {
|
|
DBGPRINT_ERR(("%s : it can't get any more information beyond AKM \n", __func__));
|
|
return NULL;
|
|
}
|
|
|
|
*count = 0;
|
|
/*DBGPRINT_ERR(("%s : The type(%d) doesn't support \n", __func__, type)); */
|
|
return NULL;
|
|
|
|
}
|
|
|
|
void WpaShowAllsuite(u8 *rsnie, u32 rsnie_len)
|
|
{
|
|
u8 *pSuite = NULL;
|
|
u8 count;
|
|
|
|
hex_dump("RSNIE", rsnie, rsnie_len);
|
|
|
|
/* group cipher */
|
|
pSuite = GetSuiteFromRSNIE(rsnie, rsnie_len, GROUP_SUITE, &count);
|
|
if (pSuite != NULL) {
|
|
hex_dump("group cipher", pSuite, 4 * count);
|
|
}
|
|
/* pairwise cipher */
|
|
pSuite = GetSuiteFromRSNIE(rsnie, rsnie_len, PAIRWISE_SUITE, &count);
|
|
if (pSuite != NULL) {
|
|
hex_dump("pairwise cipher", pSuite, 4 * count);
|
|
}
|
|
/* AKM */
|
|
pSuite = GetSuiteFromRSNIE(rsnie, rsnie_len, AKM_SUITE, &count);
|
|
if (pSuite != NULL) {
|
|
hex_dump("AKM suite", pSuite, 4 * count);
|
|
}
|
|
/* PMKID */
|
|
pSuite = GetSuiteFromRSNIE(rsnie, rsnie_len, PMKID_LIST, &count);
|
|
if (pSuite != NULL) {
|
|
hex_dump("PMKID", pSuite, LEN_PMKID);
|
|
}
|
|
|
|
}
|
|
|
|
void RTMPInsertRSNIE(u8 *pFrameBuf,
|
|
unsigned long *pFrameLen,
|
|
u8 *rsnie_ptr,
|
|
u8 rsnie_len,
|
|
u8 *pmkid_ptr, u8 pmkid_len)
|
|
{
|
|
u8 *pTmpBuf;
|
|
unsigned long TempLen = 0;
|
|
u8 extra_len = 0;
|
|
u16 pmk_count = 0;
|
|
u8 ie_num;
|
|
u8 total_len = 0;
|
|
u8 WPA2_OUI[3] = { 0x00, 0x0F, 0xAC };
|
|
|
|
pTmpBuf = pFrameBuf;
|
|
|
|
/* PMKID-List Must larger than 0 and the multiple of 16. */
|
|
if (pmkid_len > 0 && ((pmkid_len & 0x0f) == 0)) {
|
|
extra_len = sizeof(u16)+ pmkid_len;
|
|
|
|
pmk_count = (pmkid_len >> 4);
|
|
pmk_count = cpu2le16(pmk_count);
|
|
} else {
|
|
DBGPRINT(RT_DEBUG_WARN,
|
|
("%s : The length is PMKID-List is invalid (%d), so don't insert it.\n",
|
|
__func__, pmkid_len));
|
|
}
|
|
|
|
if (rsnie_len != 0) {
|
|
ie_num = IE_WPA;
|
|
total_len = rsnie_len;
|
|
|
|
if (NdisEqualMemory(rsnie_ptr + 2, WPA2_OUI, sizeof(WPA2_OUI))) {
|
|
ie_num = IE_RSN;
|
|
total_len += extra_len;
|
|
}
|
|
|
|
/* construct RSNIE body */
|
|
MakeOutgoingFrame(pTmpBuf, &TempLen,
|
|
1, &ie_num,
|
|
1, &total_len,
|
|
rsnie_len, rsnie_ptr, END_OF_ARGS);
|
|
|
|
pTmpBuf += TempLen;
|
|
*pFrameLen = *pFrameLen + TempLen;
|
|
|
|
if (ie_num == IE_RSN) {
|
|
/* Insert PMKID-List field */
|
|
if (extra_len > 0) {
|
|
MakeOutgoingFrame(pTmpBuf, &TempLen,
|
|
2, &pmk_count,
|
|
pmkid_len, pmkid_ptr,
|
|
END_OF_ARGS);
|
|
|
|
pTmpBuf += TempLen;
|
|
*pFrameLen = *pFrameLen + TempLen;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|