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