X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=drivers%2Fstaging%2Frt2860%2Fcommon%2Fcmm_wpa.c;h=6daccd94e1e1057d1fba90368c7eedaea6613909;hb=8a10a54656aff69de3530efa793cbec8d2b51d02;hp=2de29fde2c4034aac0ba6802999d754f95b9a6ea;hpb=d7757be133cc05620608af46acd178686681b7ef;p=deliverable%2Flinux.git diff --git a/drivers/staging/rt2860/common/cmm_wpa.c b/drivers/staging/rt2860/common/cmm_wpa.c index 2de29fde2c40..6daccd94e1e1 100644 --- a/drivers/staging/rt2860/common/cmm_wpa.c +++ b/drivers/staging/rt2860/common/cmm_wpa.c @@ -36,25 +36,1219 @@ Paul Lin 03-11-28 Modify for supplicant */ #include "../rt_config.h" -// WPA OUI -UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; -UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; -UCHAR OUI_WPA_WEP40[4] = {0x00, 0x50, 0xF2, 0x01}; -UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; -UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; -UCHAR OUI_WPA_WEP104[4] = {0x00, 0x50, 0xF2, 0x05}; -UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; -UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; -// WPA2 OUI -UCHAR OUI_WPA2_WEP40[4] = {0x00, 0x0F, 0xAC, 0x01}; -UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02}; -UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; -UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; -UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; -UCHAR OUI_WPA2_WEP104[4] = {0x00, 0x0F, 0xAC, 0x05}; -// MSA OUI -UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 -UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 +/* 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(IN PMAC_TABLE_ENTRY pEntry, + u8 GroupKeyWepStatus, + u8 keyDescVer, + u8 MsgType, + u8 DefaultKeyIdx, + u8 * GTK, + u8 * RSNIE, + u8 RSNIE_LEN, OUT PEAPOL_PACKET pMsg); + +static void CalculateMIC(u8 KeyDescVer, + u8 * PTK, OUT PEAPOL_PACKET pMsg); + +static void WpaEAPPacketAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem); + +static void WpaEAPOLASFAlertAction(IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM * Elem); + +static void WpaEAPOLLogoffAction(IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM * Elem); + +static void WpaEAPOLStartAction(IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM * Elem); + +static void WpaEAPOLKeyAction(IN PRTMP_ADAPTER pAd, IN 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(IN PRTMP_ADAPTER pAd, + IN 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(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem) +{ +} + +void WpaEAPOLASFAlertAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem) +{ +} + +void WpaEAPOLLogoffAction(IN PRTMP_ADAPTER pAd, IN 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(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem) +{ + MAC_TABLE_ENTRY *pEntry; + PHEADER_802_11 pHeader; + + DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLStartAction ===> \n")); + + pHeader = (PHEADER_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(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem) +{ + MAC_TABLE_ENTRY *pEntry; + PHEADER_802_11 pHeader; + PEAPOL_PACKET pEapol_packet; + KEY_INFO peerKeyInfo; + + DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLKeyAction ===>\n")); + + pHeader = (PHEADER_802_11) Elem->Msg; + pEapol_packet = + (PEAPOL_PACKET) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; + + NdisZeroMemory((u8 *)& peerKeyInfo, sizeof(peerKeyInfo)); + NdisMoveMemory((u8 *)& peerKeyInfo, + (u8 *)& pEapol_packet->KeyDesc.KeyInfo, + sizeof(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(IN PRTMP_ADAPTER pAd, + IN PMAC_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(IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY * pEntry, unsigned long TimeInterval) +{ + u8 Header802_3[14]; + 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(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(IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem) +{ + u8 PTK[80]; + u8 Header802_3[14]; + PEAPOL_PACKET pMsg1; + u32 MsgLen; + 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(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 = (PEAPOL_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(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(IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem) +{ + u8 PTK[80]; + BOOLEAN Cancelled; + PHEADER_802_11 pHeader; + EAPOL_PACKET EAPOLPKT; + PEAPOL_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(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 = (PHEADER_802_11) Elem->Msg; + + /* skip 802.11_header(24-byte) and LLC_header(8) */ + pMsg2 = (PEAPOL_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(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(IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem) +{ + PHEADER_802_11 pHeader; + u8 Header802_3[14]; + EAPOL_PACKET EAPOLPKT; + PEAPOL_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(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 = (PHEADER_802_11) Elem->Msg; + pMsg3 = (PEAPOL_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(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 */ + { + PCIPHER_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(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 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(IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem) +{ + PEAPOL_PACKET pMsg4; + PHEADER_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(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE - 2)) + break; + + if (pEntry->WpaState < AS_PTKINIT_NEGOTIATING) + break; + + /* pointer to 802.11 header */ + pHeader = (PHEADER_802_11) Elem->Msg; + + /* skip 802.11_header(24-byte) and LLC_header(8) */ + pMsg4 = + (PEAPOL_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(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(IN PRTMP_ADAPTER pAd, IN MAC_TABLE_ENTRY * pEntry) +{ + u8 Header802_3[14]; + u8 TxTsc[6]; + 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(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(IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem) +{ + u8 Header802_3[14]; + EAPOL_PACKET EAPOLPKT; + PEAPOL_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 = (PEAPOL_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(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(IN PRTMP_ADAPTER pAd, + IN MAC_TABLE_ENTRY * pEntry, + void * Msg, u32 MsgLen) +{ + u32 Len; + u8 *pData; + BOOLEAN Cancelled; + PEAPOL_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(KEY_DESCRIPTER) - + MAX_LEN_OF_RSNIE - 2)) + break; + + if (pEntry->WpaState != AS_PTKINITDONE) + break; + + pData = (u8 *)Msg; + pMsg2 = (PEAPOL_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; +} /* ======================================================================== @@ -67,72 +1261,118 @@ UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - I It is used to generate PTK, GTK or some specific random value. Arguments: - UCHAR *key, - the key material for HMAC_SHA1 use - INT key_len - the length of key - UCHAR *prefix - a prefix label - INT prefix_len - the length of the label - UCHAR *data - a specific data with variable length - INT data_len - the length of a specific data - INT len - the output lenght + 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: - UCHAR *output - the calculated result + u8 *output - the calculated result Note: 802.11i-2004 Annex H.3 ======================================================================== */ -VOID PRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *prefix, - IN INT prefix_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len) -{ - INT i; - UCHAR *input; - INT currentindex = 0; - INT total_len; - - // Allocate memory for input - os_alloc_mem(NULL, (PUCHAR *)&input, 1024); - - if (input == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n")); - return; - } - - // Generate concatenation input +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 a single octet containing 0 */ + input[prefix_len] = 0; - // Concatenate specific data + /* Concatenate specific data */ NdisMoveMemory(&input[prefix_len + 1], data, data_len); - total_len = prefix_len + 1 + data_len; + total_len = prefix_len + 1 + data_len; - // Concatenate a single octet containing 0 - // This octet shall be update later + /* Concatenate a single octet containing 0 */ + /* This octet shall be update later */ input[total_len] = 0; total_len++; - // Iterate to calculate the result by hmac-sha-1 - // Then concatenate to last result - for (i = 0; i < (len + 19) / 20; i++) - { - HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); - currentindex += 20; + /* 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 + /* update the last octet */ input[total_len - 1]++; } - os_free_mem(NULL, input); + 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; } /* @@ -143,7 +1383,7 @@ VOID PRF( It shall be called by 4-way handshake processing. Arguments: - pAd - pointer to our pAdapter context + pAd - pointer to our pAdapter context PMK - pointer to PMK ANonce - pointer to ANonce AA - pointer to Authenticator Address @@ -159,56 +1399,55 @@ VOID PRF( ======================================================================== */ -VOID WpaCountPTK( - IN PRTMP_ADAPTER pAd, - IN UCHAR *PMK, - IN UCHAR *ANonce, - IN UCHAR *AA, - IN UCHAR *SNonce, - IN UCHAR *SA, - OUT UCHAR *output, - IN UINT len) -{ - UCHAR concatenation[76]; - UINT CurrPos = 0; - UCHAR temp[32]; - UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ', - 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'}; - - // initiate the concatenation input +void WpaDerivePTK(IN PRTMP_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 + /* Get smaller address */ if (RTMPCompareMemory(SA, AA, 6) == 1) NdisMoveMemory(concatenation, AA, 6); else NdisMoveMemory(concatenation, SA, 6); CurrPos += 6; - // Get larger address + /* 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 + /* 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 + /* Get smaller Nonce */ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) - NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue + 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 + /* Get larger Nonce */ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) - NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue + 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 @@ -217,7 +1456,7 @@ VOID WpaCountPTK( hex_dump("concatenation=", concatenation, 76); - // Use PRF to generate PTK + /* Use PRF to generate PTK */ PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len); } @@ -239,46 +1478,43 @@ VOID WpaCountPTK( ======================================================================== */ -VOID GenRandom( - IN PRTMP_ADAPTER pAd, - IN UCHAR *macAddr, - OUT UCHAR *random) -{ - INT i, curr; - UCHAR local[80], KeyCounter[32]; - UCHAR result[80]; - ULONG CurrentTime; - UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'}; - - // Zero the related information +void GenRandom(IN PRTMP_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 + for (i = 0; i < 32; i++) { + /* copy the local MAC address */ COPY_MAC_ADDR(local, macAddr); - curr = MAC_ADDR_LEN; + curr = MAC_ADDR_LEN; - // concatenate the current time + /* concatenate the current time */ NdisGetSystemUpTime(&CurrentTime); - NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime)); - curr += sizeof(CurrentTime); + NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime)); + curr += sizeof(CurrentTime); - // concatenate the last result - NdisMoveMemory(&local[curr], result, 32); - curr += 32; + /* concatenate the last result */ + NdisMoveMemory(&local[curr], result, 32); + curr += 32; - // concatenate a variable - NdisMoveMemory(&local[curr], &i, 2); - curr += 2; + /* concatenate a variable */ + NdisMoveMemory(&local[curr], &i, 2); + curr += 2; - // calculate the result - PRF(KeyCounter, 32, prefix,12, local, curr, result, 32); + /* calculate the result */ + PRF(KeyCounter, 32, prefix, 12, local, curr, result, 32); } - NdisMoveMemory(random, result, 32); + NdisMoveMemory(random, result, 32); } /* @@ -290,8 +1526,8 @@ VOID GenRandom( Arguments: pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 - WepStatus - indicate the encryption type + 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 @@ -301,170 +1537,169 @@ VOID GenRandom( ======================================================================== */ -static VOID RTMPInsertRsnIeCipher( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UINT WepStatus, - IN BOOLEAN bMixCipher, - IN UCHAR FlexibleCipher, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) +static void RTMPMakeRsnIeCipher(IN PRTMP_ADAPTER pAd, + u8 ElementID, + u32 WepStatus, + IN BOOLEAN bMixCipher, + u8 FlexibleCipher, + u8 *pRsnIe, u8 * rsn_len) { - UCHAR PairwiseCnt; + u8 PairwiseCnt; *rsn_len = 0; - // decide WPA2 or WPA1 - if (ElementID == Wpa2Ie) - { - RSNIE2 *pRsnie_cipher = (RSNIE2*)pRsnIe; + /* decide WPA2 or WPA1 */ + if (ElementID == Wpa2Ie) { + RSNIE2 *pRsnie_cipher = (RSNIE2 *) pRsnIe; - // Assign the verson as 1 + /* Assign the verson as 1 */ pRsnie_cipher->version = 1; - switch (WepStatus) - { - // TKIP mode - case Ndis802_11Encryption2Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); - *rsn_len = sizeof(RSNIE2); - break; - - // AES mode - case Ndis802_11Encryption3Enabled: - if (bMixCipher) - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - else - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); - *rsn_len = sizeof(RSNIE2); - break; - - // TKIP-AES mix mode - case Ndis802_11Encryption4Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - - PairwiseCnt = 1; - // Insert WPA2 TKIP as the first pairwise cipher - if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); - // Insert WPA2 AES as the secondary pairwise cipher - if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA2_CCMP, 4); - PairwiseCnt = 2; - } - } - else - { - // Insert WPA2 AES as the first pairwise cipher - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); + switch (WepStatus) { + /* TKIP mode */ + case Ndis802_11Encryption2Enabled: + NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); + pRsnie_cipher->ucount = 1; + NdisMoveMemory(pRsnie_cipher->ucast[0].oui, + OUI_WPA2_TKIP, 4); + *rsn_len = sizeof(RSNIE2); + break; + + /* AES mode */ + case Ndis802_11Encryption3Enabled: + if (bMixCipher) + NdisMoveMemory(pRsnie_cipher->mcast, + OUI_WPA2_TKIP, 4); + else + NdisMoveMemory(pRsnie_cipher->mcast, + OUI_WPA2_CCMP, 4); + pRsnie_cipher->ucount = 1; + NdisMoveMemory(pRsnie_cipher->ucast[0].oui, + OUI_WPA2_CCMP, 4); + *rsn_len = sizeof(RSNIE2); + break; + + /* TKIP-AES mix mode */ + case Ndis802_11Encryption4Enabled: + NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); + + PairwiseCnt = 1; + /* Insert WPA2 TKIP as the first pairwise cipher */ + if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) { + NdisMoveMemory(pRsnie_cipher->ucast[0].oui, + OUI_WPA2_TKIP, 4); + /* Insert WPA2 AES as the secondary pairwise cipher */ + if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) { + NdisMoveMemory(pRsnie_cipher->ucast[0]. + oui + 4, OUI_WPA2_CCMP, + 4); + PairwiseCnt = 2; } + } else { + /* Insert WPA2 AES as the first pairwise cipher */ + NdisMoveMemory(pRsnie_cipher->ucast[0].oui, + OUI_WPA2_CCMP, 4); + } - pRsnie_cipher->ucount = PairwiseCnt; - *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1)); - break; - } + pRsnie_cipher->ucount = PairwiseCnt; + *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1)); + break; + } if ((pAd->OpMode == OPMODE_STA) && - (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) - { - UINT 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; + (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 + /* swap for big-endian platform */ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); - pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); - } - else - { - RSNIE *pRsnie_cipher = (RSNIE*)pRsnIe; + pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); + } else { + RSNIE *pRsnie_cipher = (RSNIE *) pRsnIe; - // Assign OUI and version + /* Assign OUI and version */ NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4); - pRsnie_cipher->version = 1; + pRsnie_cipher->version = 1; - switch (WepStatus) - { - // TKIP mode - case Ndis802_11Encryption2Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); - *rsn_len = sizeof(RSNIE); - break; - - // AES mode - case Ndis802_11Encryption3Enabled: - if (bMixCipher) - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - else - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); - *rsn_len = sizeof(RSNIE); - break; - - // TKIP-AES mix mode - case Ndis802_11Encryption4Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - - PairwiseCnt = 1; - // Insert WPA TKIP as the first pairwise cipher - if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); - // Insert WPA AES as the secondary pairwise cipher - if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA_CCMP, 4); - PairwiseCnt = 2; - } - } - else - { - // Insert WPA AES as the first pairwise cipher - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); + switch (WepStatus) { + /* TKIP mode */ + case Ndis802_11Encryption2Enabled: + NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); + pRsnie_cipher->ucount = 1; + NdisMoveMemory(pRsnie_cipher->ucast[0].oui, + OUI_WPA_TKIP, 4); + *rsn_len = sizeof(RSNIE); + break; + + /* AES mode */ + case Ndis802_11Encryption3Enabled: + if (bMixCipher) + NdisMoveMemory(pRsnie_cipher->mcast, + OUI_WPA_TKIP, 4); + else + NdisMoveMemory(pRsnie_cipher->mcast, + OUI_WPA_CCMP, 4); + pRsnie_cipher->ucount = 1; + NdisMoveMemory(pRsnie_cipher->ucast[0].oui, + OUI_WPA_CCMP, 4); + *rsn_len = sizeof(RSNIE); + break; + + /* TKIP-AES mix mode */ + case Ndis802_11Encryption4Enabled: + NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); + + PairwiseCnt = 1; + /* Insert WPA TKIP as the first pairwise cipher */ + if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) { + NdisMoveMemory(pRsnie_cipher->ucast[0].oui, + OUI_WPA_TKIP, 4); + /* Insert WPA AES as the secondary pairwise cipher */ + if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) { + NdisMoveMemory(pRsnie_cipher->ucast[0]. + oui + 4, OUI_WPA_CCMP, + 4); + PairwiseCnt = 2; } + } else { + /* Insert WPA AES as the first pairwise cipher */ + NdisMoveMemory(pRsnie_cipher->ucast[0].oui, + OUI_WPA_CCMP, 4); + } - pRsnie_cipher->ucount = PairwiseCnt; - *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1)); - break; - } + pRsnie_cipher->ucount = PairwiseCnt; + *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1)); + break; + } if ((pAd->OpMode == OPMODE_STA) && - (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) - { - UINT 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; + (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 + /* swap for big-endian platform */ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); - pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); + pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); } } @@ -477,8 +1712,8 @@ static VOID RTMPInsertRsnIeCipher( Arguments: pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 - AuthMode - indicate the authentication mode + ElementID - indicate the WPA1 or WPA2 + AuthMode - indicate the authentication mode apidx - indicate the interface index Return Value: @@ -487,62 +1722,66 @@ static VOID RTMPInsertRsnIeCipher( ======================================================================== */ -static VOID RTMPInsertRsnIeAKM( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UINT AuthMode, - IN UCHAR apidx, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) +static void RTMPMakeRsnIeAKM(IN PRTMP_ADAPTER pAd, + u8 ElementID, + u32 AuthMode, + u8 apidx, + u8 *pRsnIe, u8 * rsn_len) { - RSNIE_AUTH *pRsnie_auth; + RSNIE_AUTH *pRsnie_auth; + u8 AkmCnt = 1; /* default as 1 */ + + pRsnie_auth = (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; - pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len)); - - // decide WPA2 or WPA1 - if (ElementID == Wpa2Ie) - { - switch (AuthMode) - { - case Ndis802_11AuthModeWPA2: - case Ndis802_11AuthModeWPA1WPA2: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4); - break; - - case Ndis802_11AuthModeWPA2PSK: - case Ndis802_11AuthModeWPA1PSKWPA2PSK: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4); - break; - } - } - else - { - switch (AuthMode) - { - case Ndis802_11AuthModeWPA: - case Ndis802_11AuthModeWPA1WPA2: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4); - break; - - case Ndis802_11AuthModeWPAPSK: - case Ndis802_11AuthModeWPA1PSKWPA2PSK: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4); - break; - - case Ndis802_11AuthModeWPANone: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4); - break; - } + } + } 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); - (*rsn_len) += sizeof(RSNIE_AUTH); // update current RSNIE length + /* update current RSNIE length */ + (*rsn_len) += (sizeof(RSNIE_AUTH) + (4 * (AkmCnt - 1))); } @@ -555,7 +1794,7 @@ static VOID RTMPInsertRsnIeAKM( Arguments: pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 + ElementID - indicate the WPA1 or WPA2 apidx - indicate the interface index Return Value: @@ -564,29 +1803,25 @@ static VOID RTMPInsertRsnIeAKM( ======================================================================== */ -static VOID RTMPInsertRsnIeCap( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UCHAR apidx, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) +static void RTMPMakeRsnIeCap(IN PRTMP_ADAPTER pAd, + u8 ElementID, + u8 apidx, + u8 *pRsnIe, u8 * rsn_len) { - RSN_CAPABILITIES *pRSN_Cap; + RSN_CAPABILITIES *pRSN_Cap; - // it could be ignored in WPA1 mode + /* it could be ignored in WPA1 mode */ if (ElementID == WpaIe) return; - pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len)); - + pRSN_Cap = (RSN_CAPABILITIES *) (pRsnIe + (*rsn_len)); pRSN_Cap->word = cpu2le16(pRSN_Cap->word); - (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length + (*rsn_len) += sizeof(RSN_CAPABILITIES); /* update current RSNIE length */ } - /* ======================================================================== @@ -595,8 +1830,8 @@ static VOID RTMPInsertRsnIeCap( Arguments: pAd - pointer to our pAdapter context - AuthMode - indicate the authentication mode - WepStatus - indicate the encryption type + AuthMode - indicate the authentication mode + WepStatus - indicate the encryption type apidx - indicate the interface index Return Value: @@ -605,48 +1840,43 @@ static VOID RTMPInsertRsnIeCap( ======================================================================== */ -VOID RTMPMakeRSNIE( - IN PRTMP_ADAPTER pAd, - IN UINT AuthMode, - IN UINT WepStatus, - IN UCHAR apidx) -{ - PUCHAR pRsnIe = NULL; // primary RSNIE - UCHAR *rsnielen_cur_p = 0; // the length of the primary RSNIE - UCHAR *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE - UCHAR PrimaryRsnie; - BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different - UCHAR p_offset; - WPA_MIX_PAIR_CIPHER FlexibleCipher = WPA_TKIPAES_WPA2_TKIPAES; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode +void RTMPMakeRSNIE(IN PRTMP_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 (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 + } 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) - ) + (AuthMode != Ndis802_11AuthModeWPA2PSK) && + (AuthMode != Ndis802_11AuthModeWPANone) + ) return; } - DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n")); + DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPMakeRSNIE(STA)\n")); - // Zero RSNIE context + /* Zero RSNIE context */ pAd->StaCfg.RSNIE_Len = 0; NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE); - // Pointer to RSNIE + /* Pointer to RSNIE */ rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len; pRsnIe = pAd->StaCfg.RSN_IE; @@ -654,34 +1884,35 @@ VOID RTMPMakeRSNIE( } } - // indicate primary RSNIE as WPA or WPA2 + /* indicate primary RSNIE as WPA or WPA2 */ if ((AuthMode == Ndis802_11AuthModeWPA) || - (AuthMode == Ndis802_11AuthModeWPAPSK) || - (AuthMode == Ndis802_11AuthModeWPANone) || - (AuthMode == Ndis802_11AuthModeWPA1WPA2) || - (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK)) + (AuthMode == Ndis802_11AuthModeWPAPSK) || + (AuthMode == Ndis802_11AuthModeWPANone) || + (AuthMode == Ndis802_11AuthModeWPA1WPA2) || + (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK)) PrimaryRsnie = WpaIe; else PrimaryRsnie = Wpa2Ie; { - // Build the primary RSNIE - // 1. insert cipher suite - RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset); + /* Build the primary RSNIE */ + /* 1. insert cipher suite */ + RTMPMakeRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, + FlexibleCipher, pRsnIe, &p_offset); - // 2. insert AKM - RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset); + /* 2. insert AKM */ + RTMPMakeRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, + &p_offset); - // 3. insert capability - RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset); + /* 3. insert capability */ + RTMPMakeRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset); } - // 4. update the RSNIE length + /* 4. update the RSNIE length */ *rsnielen_cur_p = p_offset; hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p)); - } /* @@ -693,144 +1924,1093 @@ VOID RTMPMakeRSNIE( pAd - pointer to our pAdapter context pEntry - pointer to active entry pData - the received frame - DataByteCount - the received frame's length + DataByteCount - the received frame's length FromWhichBSSID - indicate the interface index Return: - TRUE - This frame is EAP frame - FALSE - otherwise + TRUE - This frame is EAP frame + FALSE - otherwise ========================================================================== */ -BOOLEAN RTMPCheckWPAframe( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR pData, - IN ULONG DataByteCount, - IN UCHAR FromWhichBSSID) -{ - ULONG Body_len; +BOOLEAN RTMPCheckWPAframe(IN PRTMP_ADAPTER pAd, + IN PMAC_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(IN PRTMP_ADAPTER pAd, + u8 *pData, + u8 DataLen, + IN MAC_TABLE_ENTRY * pEntry, u8 * Offset) +{ + u8 *pVIE; + u8 len; + PEID_STRUCT pEid; + BOOLEAN result = FALSE; + + pVIE = pData; + len = DataLen; + *Offset = 0; + + while (len > sizeof(RSNIE2)) { + pEid = (PEID_STRUCT) pVIE; + /* WPA RSN IE */ + if ((pEid->Eid == IE_WPA) + && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) { + if ((pEntry->AuthMode == Ndis802_11AuthModeWPA + || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) + && + (NdisEqualMemory + (pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) + && (pEntry->RSNIE_Len == (pEid->Len + 2))) { + result = TRUE; + } + + *Offset += (pEid->Len + 2); + } + /* WPA2 RSN IE */ + else if ((pEid->Eid == IE_RSN) + && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) { + if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2 + || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) + && (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; - 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; } /* ======================================================================== Routine Description: - Misc function to decrypt AES body + 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: - This function references to RFC 3394 for aes key unwrap algorithm. + 802.11i D10 ======================================================================== */ -VOID AES_GTK_KEY_UNWRAP( - IN UCHAR *key, - OUT UCHAR *plaintext, - IN UCHAR c_len, - IN UCHAR *ciphertext) +BOOLEAN RTMPParseEapolKeyData(IN PRTMP_ADAPTER pAd, + u8 *pKeyData, + u8 KeyDataLen, + u8 GroupKeyIndex, + u8 MsgType, + IN BOOLEAN bWPA2, IN MAC_TABLE_ENTRY * pEntry) +{ + PKDE_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 = (PKDE_ENCAP) pMyKeyData; + + DefaultIdx = pKDE->GTKEncap.Kid; + + /* Sanity check - KED length */ + if (KeyDataLength < (pKDE->Len + 2)) { + DBGPRINT(RT_DEBUG_ERROR, + ("ERROR: The len from KDE is too short \n")); + return FALSE; + } + /* Get GTK length - refer to IEEE 802.11i-2004 p.82 */ + GTKLEN = pKDE->Len - 6; + if (GTKLEN < LEN_AES_KEY) { + DBGPRINT(RT_DEBUG_ERROR, + ("ERROR: GTK Key length is too short (%d) \n", + GTKLEN)); + return FALSE; + } + + } else { + DBGPRINT(RT_DEBUG_ERROR, + ("ERROR: KDE format length is too short \n")); + return FALSE; + } + + DBGPRINT(RT_DEBUG_TRACE, + ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n", + DefaultIdx, GTKLEN)); + /* skip it */ + pMyKeyData += 8; + KeyDataLength -= 8; + + } else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1) { + DefaultIdx = GroupKeyIndex; + DBGPRINT(RT_DEBUG_TRACE, + ("GTK DefaultKeyID=%d \n", DefaultIdx)); + } + /* Sanity check - shared key index must be 1 ~ 3 */ + if (DefaultIdx < 1 || DefaultIdx > 3) { + DBGPRINT(RT_DEBUG_ERROR, + ("ERROR: GTK Key index(%d) is invalid in %s %s \n", + DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"), + GetEapolMsgType(MsgType))); + return FALSE; + } + + { + PCIPHER_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(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(IN PMAC_TABLE_ENTRY pEntry, + u8 GroupKeyWepStatus, + u8 MsgType, + u8 DefaultKeyIdx, + u8 * KeyNonce, + u8 * TxRSC, + u8 * GTK, + u8 * RSNIE, + u8 RSNIE_Len, OUT PEAPOL_PACKET pMsg) { - UCHAR A[8], BIN[16], BOUT[16]; - UCHAR xor; - INT i, j; - aes_context aesctx; - UCHAR *R; - INT num_blocks = c_len/8; // unit:64bits + BOOLEAN bWPA2 = FALSE; + u8 KeyDescVer; + /* Choose WPA2 or not */ + if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) || + (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) + bWPA2 = TRUE; - os_alloc_mem(NULL, (PUCHAR *)&R, 512); + /* Init Packet and Fill header */ + pMsg->ProVer = EAPOL_VER; + pMsg->ProType = EAPOLKey; - if (R == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n")); - return; - } /* End of if */ + /* 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; - // Initialize - NdisMoveMemory(A, ciphertext, 8); - //Input plaintext - for(i = 0; i < (c_len-8); i++) + /* Key Descriptor Version (bits 0-2) specifies the key descriptor version type */ { - R[ i] = ciphertext[i + 8]; + /* 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)); } - rtmp_aes_set_key(&aesctx, key, 128); + pMsg->KeyDesc.KeyInfo.KeyDescVer = KeyDescVer; - for(j = 5; j >= 0; j--) + /* 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 */ { - for(i = (num_blocks-1); i > 0; i--) - { - xor = (num_blocks -1 )* j + i; - NdisMoveMemory(BIN, A, 8); - BIN[7] = A[7] ^ xor; - NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8); - rtmp_aes_decrypt(&aesctx, BIN, BOUT); - NdisMoveMemory(A, &BOUT[0], 8); - NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8); + 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); } } - // OUTPUT - for(i = 0; i < c_len; i++) - { - plaintext[i] = R[i]; + /* 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(IN PMAC_TABLE_ENTRY pEntry, + u8 GroupKeyWepStatus, + u8 keyDescVer, + u8 MsgType, + u8 DefaultKeyIdx, + u8 * GTK, + u8 * RSNIE, + u8 RSNIE_LEN, OUT PEAPOL_PACKET pMsg) +{ + u8 *mpool, *Key_Data, *Rc4GTK; + u8 ekey[(LEN_KEY_DESC_IV + LEN_EAP_EK)]; + unsigned long data_offset; + BOOLEAN bWPA2Capable = FALSE; + PRTMP_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, OUT PEAPOL_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(IN PRTMP_ADAPTER pAd, + IN RX_BLK * pRxBlk, + IN NDIS_802_11_ENCRYPTION_STATUS + GroupCipher, IN PCIPHER_KEY pShard_key) +{ + PRXWI_STRUC pRxWI = pRxBlk->pRxWI; + + /* handle WEP decryption */ + if (GroupCipher == Ndis802_11Encryption1Enabled) { + if (RTMPSoftDecryptWEP + (pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, + pShard_key)) { + + /*Minus IV[4] & ICV[4] */ + pRxWI->MPDUtotalByteCount -= 8; + } else { + DBGPRINT(RT_DEBUG_ERROR, + ("ERROR : Software decrypt WEP data fails.\n")); + /* give up this frame */ + return NDIS_STATUS_FAILURE; + } + } + /* handle TKIP decryption */ + else if (GroupCipher == Ndis802_11Encryption2Enabled) { + if (RTMPSoftDecryptTKIP + (pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0, + pShard_key)) { + + /*Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV */ + pRxWI->MPDUtotalByteCount -= 20; + } else { + DBGPRINT(RT_DEBUG_ERROR, + ("ERROR : RTMPSoftDecryptTKIP Failed\n")); + /* give up this frame */ + return NDIS_STATUS_FAILURE; + } + } + /* handle AES decryption */ + else if (GroupCipher == Ndis802_11Encryption3Enabled) { + if (RTMPSoftDecryptAES + (pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, + pShard_key)) { + + /*8 bytes MIC, 8 bytes IV/EIV (CCMP Header) */ + pRxWI->MPDUtotalByteCount -= 16; + } else { + DBGPRINT(RT_DEBUG_ERROR, + ("ERROR : RTMPSoftDecryptAES Failed\n")); + /* give up this frame */ + return NDIS_STATUS_FAILURE; + } + } else { + /* give up this frame */ + return NDIS_STATUS_FAILURE; + } + + return NDIS_STATUS_SUCCESS; + +} + +u8 *GetSuiteFromRSNIE(u8 *rsnie, + u32 rsnie_len, u8 type, u8 * count) +{ + PEID_STRUCT pEid; + int len; + u8 *pBuf; + int offset = 0; + PRSNIE_AUTH pAkm; + u16 acount; + BOOLEAN isWPA2 = FALSE; + + pEid = (PEID_STRUCT) 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) { + PRSNIE pRsnie = (PRSNIE) pBuf; + u16 ucount; + + if (len < sizeof(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(RSNIE) + (4 * (ucount - 1)); + + } else if (pEid->Eid == IE_RSN) { + PRSNIE2 pRsnie = (PRSNIE2) pBuf; + u16 ucount; + + isWPA2 = TRUE; + + if (len < sizeof(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(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(RSNIE_AUTH)) { + DBGPRINT_ERR(("%s : The length of RSNIE is too short\n", + __func__)); + return NULL; + } + /* pointer to AKM count */ + pAkm = (PRSNIE_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(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 */ + if ((pSuite = + GetSuiteFromRSNIE(rsnie, rsnie_len, GROUP_SUITE, + &count)) != NULL) { + hex_dump("group cipher", pSuite, 4 * count); + } + /* pairwise cipher */ + if ((pSuite = + GetSuiteFromRSNIE(rsnie, rsnie_len, PAIRWISE_SUITE, + &count)) != NULL) { + hex_dump("pairwise cipher", pSuite, 4 * count); + } + /* AKM */ + if ((pSuite = + GetSuiteFromRSNIE(rsnie, rsnie_len, AKM_SUITE, &count)) != NULL) { + hex_dump("AKM suite", pSuite, 4 * count); + } + /* PMKID */ + if ((pSuite = + GetSuiteFromRSNIE(rsnie, rsnie_len, PMKID_LIST, &count)) != 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; + } + } + } - os_free_mem(NULL, R); + return; }