| /* |
| ************************************************************************* |
| * 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" |
| |
| 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 disassoicate 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); |
| |
| } |