📄 cmm_wpa.c
字号:
/* ************************************************************************* * Ralink Tech Inc. * 5F., No.36, Taiyuan St., Jhubei City, * Hsinchu County 302, * Taiwan, R.O.C. * * (c) Copyright 2002-2007, Ralink Technology, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * ************************************************************************* Module Name: wpa.c Abstract: Revision History: Who When What -------- ---------- ---------------------------------------------- Jan Lee 03-07-22 Initial Paul Lin 03-11-28 Modify for supplicant*/#include "rt_config.h"// WPA OUIUCHAR 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 OUIUCHAR 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};static VOID ConstructEapolKeyData( IN PMAC_TABLE_ENTRY pEntry, IN UCHAR GroupKeyWepStatus, IN UCHAR keyDescVer, IN UCHAR MsgType, IN UCHAR DefaultKeyIdx, IN UCHAR *GTK, IN UCHAR *RSNIE, IN UCHAR RSNIE_LEN, OUT PEAPOL_PACKET pMsg);static VOID CalculateMIC( IN UCHAR KeyDescVer, IN UCHAR *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((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&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)); *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&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_UINT16(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 PNDIS_PACKET 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, IN PUCHAR pHeader802_3, IN UINT HdrLen, IN PUCHAR pData, IN UINT DataLen, IN BOOLEAN bClearFrame){ PNDIS_PACKET pPacket; NDIS_STATUS 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, (UCHAR)pEntry->Aid); RTMP_SET_PACKET_MOREDATA(pPacket, FALSE); }#ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // send out the packet Status = STASendPacket(pAd, pPacket); if (Status == NDIS_STATUS_SUCCESS) { UCHAR 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); } } }#endif // CONFIG_STA_SUPPORT // } while (FALSE);}/* ========================================================================== Description: This is a function to initilize 4-way handshake Return: ==========================================================================*/VOID WPAStart4WayHS( IN PRTMP_ADAPTER pAd, IN MAC_TABLE_ENTRY *pEntry, IN ULONG TimeInterval) { UCHAR Header802_3[14]; EAPOL_PACKET EAPOLPKT; PUINT8 pBssid = NULL; UCHAR group_cipher = Ndis802_11WEPDisabled;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -