/* ************************************************************************* * 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 Justin P. Mattock 11/07/2010 Fix typos */ #include "../rt_config.h" void inc_byte_array(u8 * counter, int len); /* ======================================================================== Routine Description: Process MIC error indication and record MIC error timer. Arguments: pAd Pointer to our adapter pWpaKey Pointer to the WPA key structure Return Value: None IRQL = DISPATCH_LEVEL Note: ======================================================================== */ void RTMPReportMicError(struct rt_rtmp_adapter *pAd, struct rt_cipher_key *pWpaKey) { unsigned long Now; u8 unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1 : 0); /* Record Last MIC error time and count */ NdisGetSystemUpTime(&Now); if (pAd->StaCfg.MicErrCnt == 0) { pAd->StaCfg.MicErrCnt++; pAd->StaCfg.LastMicErrorTime = Now; NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); } else if (pAd->StaCfg.MicErrCnt == 1) { if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now) { /* Update Last MIC error time, this did not violate two MIC errors within 60 seconds */ pAd->StaCfg.LastMicErrorTime = Now; } else { if (pAd->CommonCfg.bWirelessEvent) RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab. Content[BSSID_WCID].Addr, BSS0, 0); pAd->StaCfg.LastMicErrorTime = Now; /* Violate MIC error counts, MIC countermeasures kicks in */ pAd->StaCfg.MicErrCnt++; /* We shall block all reception */ /* We shall clean all Tx ring and disassociate from AP after next EAPOL frame */ /* */ /* No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets */ /* if pAd->StaCfg.MicErrCnt greater than 2. */ /* */ /* RTMPRingCleanUp(pAd, QID_AC_BK); */ /* RTMPRingCleanUp(pAd, QID_AC_BE); */ /* RTMPRingCleanUp(pAd, QID_AC_VI); */ /* RTMPRingCleanUp(pAd, QID_AC_VO); */ /* RTMPRingCleanUp(pAd, QID_HCCA); */ } } else { /* MIC error count >= 2 */ /* This should not happen */ ; } MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, OID_802_11_MIC_FAILURE_REPORT_FRAME, 1, &unicastKey); if (pAd->StaCfg.MicErrCnt == 2) { RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100); } } #define LENGTH_EAP_H 4 /* If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). */ int WpaCheckEapCode(struct rt_rtmp_adapter *pAd, u8 *pFrame, u16 FrameLen, u16 OffSet) { u8 *pData; int result = 0; if (FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H) return result; pData = pFrame + OffSet; /* skip offset bytes */ if (*(pData + 1) == EAPPacket) /* 802.1x header - Packet Type */ { result = *(pData + 4); /* EAP header - Code */ } return result; } void WpaSendMicFailureToWpaSupplicant(struct rt_rtmp_adapter *pAd, IN BOOLEAN bUnicast) { char custom[IW_CUSTOM_MAX] = { 0 }; sprintf(custom, "MLME-MICHAELMICFAILURE.indication"); if (bUnicast) sprintf(custom, "%s unicast", custom); RtmpOSWrielessEventSend(pAd, IWEVCUSTOM, -1, NULL, (u8 *)custom, strlen(custom)); return; } void WpaMicFailureReportFrame(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem) { u8 *pOutBuffer = NULL; u8 Header802_3[14]; unsigned long FrameLen = 0; struct rt_eapol_packet Packet; u8 Mic[16]; BOOLEAN bUnicast; DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n")); bUnicast = (Elem->Msg[0] == 1 ? TRUE : FALSE); pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER); /* init 802.3 header and Fill Packet */ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); NdisZeroMemory(&Packet, sizeof(Packet)); Packet.ProVer = EAPOL_VER; Packet.ProType = EAPOLKey; Packet.KeyDesc.Type = WPA1_KEY_DESC; /* Request field presented */ Packet.KeyDesc.KeyInfo.Request = 1; if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { Packet.KeyDesc.KeyInfo.KeyDescVer = 2; } else /* TKIP */ { Packet.KeyDesc.KeyInfo.KeyDescVer = 1; } Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY); /* KeyMic field presented */ Packet.KeyDesc.KeyInfo.KeyMic = 1; /* Error field presented */ Packet.KeyDesc.KeyInfo.Error = 1; /* Update packet length after decide Key data payload */ SET_u16_TO_ARRARY(Packet.Body_Len, LEN_EAPOL_KEY_MSG) /* Key Replay Count */ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); inc_byte_array(pAd->StaCfg.ReplayCounter, 8); /* Convert to little-endian format. */ *((u16 *) & Packet.KeyDesc.KeyInfo) = cpu2le16(*((u16 *) & Packet.KeyDesc.KeyInfo)); MlmeAllocateMemory(pAd, (u8 **) & pOutBuffer); /* allocate memory */ if (pOutBuffer == NULL) { return; } /* Prepare EAPOL frame for MIC calculation */ /* Be careful, only EAPOL frame is counted for MIC calculation */ MakeOutgoingFrame(pOutBuffer, &FrameLen, CONV_ARRARY_TO_u16(Packet.Body_Len) + 4, &Packet, END_OF_ARGS); /* Prepare and Fill MIC value */ NdisZeroMemory(Mic, sizeof(Mic)); if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { /* AES */ u8 digest[20] = { 0 }; HMAC_SHA1(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, digest, SHA1_DIGEST_SIZE); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { /* TKIP */ HMAC_MD5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic, MD5_DIGEST_SIZE); } NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); /* copy frame to Tx ring and send MIC failure report frame to authenticator */ RTMPToWirelessSta(pAd, &pAd->MacTab.Content[BSSID_WCID], Header802_3, LENGTH_802_3, (u8 *)& Packet, CONV_ARRARY_TO_u16(Packet.Body_Len) + 4, FALSE); MlmeFreeMemory(pAd, (u8 *)pOutBuffer); DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n")); } /** from wpa_supplicant * inc_byte_array - Increment arbitrary length byte array by one * @counter: Pointer to byte array * @len: Length of the counter in bytes * * This function increments the last byte of the counter by one and continues * rolling over to more significant bytes if the byte was incremented from * 0xff to 0x00. */ void inc_byte_array(u8 * counter, int len) { int pos = len - 1; while (pos >= 0) { counter[pos]++; if (counter[pos] != 0) break; pos--; } } void WpaDisassocApAndBlockAssoc(void *SystemSpecific1, void *FunctionContext, void *SystemSpecific2, void *SystemSpecific3) { struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext; struct rt_mlme_disassoc_req DisassocReq; /* disassoc from current AP first */ DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n")); DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE); MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(struct rt_mlme_disassoc_req), &DisassocReq); pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; pAd->StaCfg.bBlockAssoc = TRUE; } void WpaStaPairwiseKeySetting(struct rt_rtmp_adapter *pAd) { struct rt_cipher_key *pSharedKey; struct rt_mac_table_entry *pEntry; pEntry = &pAd->MacTab.Content[BSSID_WCID]; /* Pairwise key shall use key#0 */ 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 */ 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); STA_PORT_SECURED(pAd); pAd->IndicateMediaState = NdisMediaStateConnected; DBGPRINT(RT_DEBUG_TRACE, ("%s : AID(%d) port secured\n", __func__, pEntry->Aid)); } void WpaStaGroupKeySetting(struct rt_rtmp_adapter *pAd) { struct rt_cipher_key *pSharedKey; 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); }