1/* 2 ************************************************************************* 3 * Ralink Tech Inc. 4 * 5F., No.36, Taiyuan St., Jhubei City, 5 * Hsinchu County 302, 6 * Taiwan, R.O.C. 7 * 8 * (c) Copyright 2002-2007, Ralink Technology, Inc. 9 * 10 * This program is free software; you can redistribute it and/or modify * 11 * it under the terms of the GNU General Public License as published by * 12 * the Free Software Foundation; either version 2 of the License, or * 13 * (at your option) any later version. * 14 * * 15 * This program is distributed in the hope that it will be useful, * 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 * GNU General Public License for more details. * 19 * * 20 * You should have received a copy of the GNU General Public License * 21 * along with this program; if not, write to the * 22 * Free Software Foundation, Inc., * 23 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 24 * * 25 ************************************************************************* 26 27 Module Name: 28 wpa.c 29 30 Abstract: 31 32 Revision History: 33 Who When What 34 -------- ---------- ---------------------------------------------- 35 Jan Lee 03-07-22 Initial 36 Paul Lin 03-11-28 Modify for supplicant 37*/ 38#include "../rt_config.h" 39 40void inc_byte_array(u8 * counter, int len); 41 42/* 43 ======================================================================== 44 45 Routine Description: 46 Process MIC error indication and record MIC error timer. 47 48 Arguments: 49 pAd Pointer to our adapter 50 pWpaKey Pointer to the WPA key structure 51 52 Return Value: 53 None 54 55 IRQL = DISPATCH_LEVEL 56 57 Note: 58 59 ======================================================================== 60*/ 61void RTMPReportMicError(struct rt_rtmp_adapter *pAd, struct rt_cipher_key *pWpaKey) 62{ 63 unsigned long Now; 64 u8 unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1 : 0); 65 66 /* Record Last MIC error time and count */ 67 NdisGetSystemUpTime(&Now); 68 if (pAd->StaCfg.MicErrCnt == 0) { 69 pAd->StaCfg.MicErrCnt++; 70 pAd->StaCfg.LastMicErrorTime = Now; 71 NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); 72 } else if (pAd->StaCfg.MicErrCnt == 1) { 73 if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now) { 74 /* Update Last MIC error time, this did not violate two MIC errors within 60 seconds */ 75 pAd->StaCfg.LastMicErrorTime = Now; 76 } else { 77 78 if (pAd->CommonCfg.bWirelessEvent) 79 RTMPSendWirelessEvent(pAd, 80 IW_COUNTER_MEASURES_EVENT_FLAG, 81 pAd->MacTab. 82 Content[BSSID_WCID].Addr, 83 BSS0, 0); 84 85 pAd->StaCfg.LastMicErrorTime = Now; 86 /* Violate MIC error counts, MIC countermeasures kicks in */ 87 pAd->StaCfg.MicErrCnt++; 88 /* We shall block all reception */ 89 /* We shall clean all Tx ring and disassoicate from AP after next EAPOL frame */ 90 /* */ 91 /* No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets */ 92 /* if pAd->StaCfg.MicErrCnt greater than 2. */ 93 /* */ 94 /* RTMPRingCleanUp(pAd, QID_AC_BK); */ 95 /* RTMPRingCleanUp(pAd, QID_AC_BE); */ 96 /* RTMPRingCleanUp(pAd, QID_AC_VI); */ 97 /* RTMPRingCleanUp(pAd, QID_AC_VO); */ 98 /* RTMPRingCleanUp(pAd, QID_HCCA); */ 99 } 100 } else { 101 /* MIC error count >= 2 */ 102 /* This should not happen */ 103 ; 104 } 105 MlmeEnqueue(pAd, 106 MLME_CNTL_STATE_MACHINE, 107 OID_802_11_MIC_FAILURE_REPORT_FRAME, 1, &unicastKey); 108 109 if (pAd->StaCfg.MicErrCnt == 2) { 110 RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100); 111 } 112} 113 114#define LENGTH_EAP_H 4 115/* If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). */ 116int WpaCheckEapCode(struct rt_rtmp_adapter *pAd, 117 u8 *pFrame, u16 FrameLen, u16 OffSet) 118{ 119 120 u8 *pData; 121 int result = 0; 122 123 if (FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H) 124 return result; 125 126 pData = pFrame + OffSet; /* skip offset bytes */ 127 128 if (*(pData + 1) == EAPPacket) /* 802.1x header - Packet Type */ 129 { 130 result = *(pData + 4); /* EAP header - Code */ 131 } 132 133 return result; 134} 135 136void WpaSendMicFailureToWpaSupplicant(struct rt_rtmp_adapter *pAd, IN BOOLEAN bUnicast) 137{ 138 char custom[IW_CUSTOM_MAX] = { 0 }; 139 140 sprintf(custom, "MLME-MICHAELMICFAILURE.indication"); 141 if (bUnicast) 142 sprintf(custom, "%s unicast", custom); 143 144 RtmpOSWrielessEventSend(pAd, IWEVCUSTOM, -1, NULL, (u8 *)custom, 145 strlen(custom)); 146 147 return; 148} 149 150void WpaMicFailureReportFrame(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem) 151{ 152 u8 *pOutBuffer = NULL; 153 u8 Header802_3[14]; 154 unsigned long FrameLen = 0; 155 struct rt_eapol_packet Packet; 156 u8 Mic[16]; 157 BOOLEAN bUnicast; 158 159 DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n")); 160 161 bUnicast = (Elem->Msg[0] == 1 ? TRUE : FALSE); 162 pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER); 163 164 /* init 802.3 header and Fill Packet */ 165 MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, 166 pAd->CurrentAddress, EAPOL); 167 168 NdisZeroMemory(&Packet, sizeof(Packet)); 169 Packet.ProVer = EAPOL_VER; 170 Packet.ProType = EAPOLKey; 171 172 Packet.KeyDesc.Type = WPA1_KEY_DESC; 173 174 /* Request field presented */ 175 Packet.KeyDesc.KeyInfo.Request = 1; 176 177 if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { 178 Packet.KeyDesc.KeyInfo.KeyDescVer = 2; 179 } else /* TKIP */ 180 { 181 Packet.KeyDesc.KeyInfo.KeyDescVer = 1; 182 } 183 184 Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY); 185 186 /* KeyMic field presented */ 187 Packet.KeyDesc.KeyInfo.KeyMic = 1; 188 189 /* Error field presented */ 190 Packet.KeyDesc.KeyInfo.Error = 1; 191 192 /* Update packet length after decide Key data payload */ 193 SET_u16_TO_ARRARY(Packet.Body_Len, LEN_EAPOL_KEY_MSG) 194 /* Key Replay Count */ 195 NdisMoveMemory(Packet.KeyDesc.ReplayCounter, 196 pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); 197 inc_byte_array(pAd->StaCfg.ReplayCounter, 8); 198 199 /* Convert to little-endian format. */ 200 *((u16 *) & Packet.KeyDesc.KeyInfo) = 201 cpu2le16(*((u16 *) & Packet.KeyDesc.KeyInfo)); 202 203 MlmeAllocateMemory(pAd, (u8 **) & pOutBuffer); /* allocate memory */ 204 if (pOutBuffer == NULL) { 205 return; 206 } 207 /* Prepare EAPOL frame for MIC calculation */ 208 /* Be careful, only EAPOL frame is counted for MIC calculation */ 209 MakeOutgoingFrame(pOutBuffer, &FrameLen, 210 CONV_ARRARY_TO_u16(Packet.Body_Len) + 4, &Packet, 211 END_OF_ARGS); 212 213 /* Prepare and Fill MIC value */ 214 NdisZeroMemory(Mic, sizeof(Mic)); 215 if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { /* AES */ 216 u8 digest[20] = { 0 }; 217 HMAC_SHA1(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, 218 digest, SHA1_DIGEST_SIZE); 219 NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); 220 } else { /* TKIP */ 221 HMAC_MD5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, 222 Mic, MD5_DIGEST_SIZE); 223 } 224 NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); 225 226 /* copy frame to Tx ring and send MIC failure report frame to authenticator */ 227 RTMPToWirelessSta(pAd, &pAd->MacTab.Content[BSSID_WCID], 228 Header802_3, LENGTH_802_3, 229 (u8 *)& Packet, 230 CONV_ARRARY_TO_u16(Packet.Body_Len) + 4, FALSE); 231 232 MlmeFreeMemory(pAd, (u8 *)pOutBuffer); 233 234 DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n")); 235} 236 237/** from wpa_supplicant 238 * inc_byte_array - Increment arbitrary length byte array by one 239 * @counter: Pointer to byte array 240 * @len: Length of the counter in bytes 241 * 242 * This function increments the last byte of the counter by one and continues 243 * rolling over to more significant bytes if the byte was incremented from 244 * 0xff to 0x00. 245 */ 246void inc_byte_array(u8 * counter, int len) 247{ 248 int pos = len - 1; 249 while (pos >= 0) { 250 counter[pos]++; 251 if (counter[pos] != 0) 252 break; 253 pos--; 254 } 255} 256 257void WpaDisassocApAndBlockAssoc(void *SystemSpecific1, 258 void *FunctionContext, 259 void *SystemSpecific2, 260 void *SystemSpecific3) 261{ 262 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext; 263 struct rt_mlme_disassoc_req DisassocReq; 264 265 /* disassoc from current AP first */ 266 DBGPRINT(RT_DEBUG_TRACE, 267 ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n")); 268 DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, 269 REASON_MIC_FAILURE); 270 MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, 271 sizeof(struct rt_mlme_disassoc_req), &DisassocReq); 272 273 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; 274 pAd->StaCfg.bBlockAssoc = TRUE; 275} 276 277void WpaStaPairwiseKeySetting(struct rt_rtmp_adapter *pAd) 278{ 279 struct rt_cipher_key *pSharedKey; 280 struct rt_mac_table_entry *pEntry; 281 282 pEntry = &pAd->MacTab.Content[BSSID_WCID]; 283 284 /* Pairwise key shall use key#0 */ 285 pSharedKey = &pAd->SharedKey[BSS0][0]; 286 287 NdisMoveMemory(pAd->StaCfg.PTK, pEntry->PTK, LEN_PTK); 288 289 /* Prepare pair-wise key information into shared key table */ 290 NdisZeroMemory(pSharedKey, sizeof(struct rt_cipher_key)); 291 pSharedKey->KeyLen = LEN_TKIP_EK; 292 NdisMoveMemory(pSharedKey->Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); 293 NdisMoveMemory(pSharedKey->RxMic, &pAd->StaCfg.PTK[48], 294 LEN_TKIP_RXMICK); 295 NdisMoveMemory(pSharedKey->TxMic, 296 &pAd->StaCfg.PTK[48 + LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); 297 298 /* Decide its ChiperAlg */ 299 if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) 300 pSharedKey->CipherAlg = CIPHER_TKIP; 301 else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) 302 pSharedKey->CipherAlg = CIPHER_AES; 303 else 304 pSharedKey->CipherAlg = CIPHER_NONE; 305 306 /* Update these related information to struct rt_mac_table_entry */ 307 NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], 308 LEN_TKIP_EK); 309 NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], 310 LEN_TKIP_RXMICK); 311 NdisMoveMemory(pEntry->PairwiseKey.TxMic, 312 &pAd->StaCfg.PTK[48 + LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); 313 pEntry->PairwiseKey.CipherAlg = pSharedKey->CipherAlg; 314 315 /* Update pairwise key information to ASIC Shared Key Table */ 316 AsicAddSharedKeyEntry(pAd, 317 BSS0, 318 0, 319 pSharedKey->CipherAlg, 320 pSharedKey->Key, 321 pSharedKey->TxMic, pSharedKey->RxMic); 322 323 /* Update ASIC WCID attribute table and IVEIV table */ 324 RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pSharedKey->CipherAlg, pEntry); 325 STA_PORT_SECURED(pAd); 326 pAd->IndicateMediaState = NdisMediaStateConnected; 327 328 DBGPRINT(RT_DEBUG_TRACE, 329 ("%s : AID(%d) port secured\n", __func__, pEntry->Aid)); 330 331} 332 333void WpaStaGroupKeySetting(struct rt_rtmp_adapter *pAd) 334{ 335 struct rt_cipher_key *pSharedKey; 336 337 pSharedKey = &pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId]; 338 339 /* Prepare pair-wise key information into shared key table */ 340 NdisZeroMemory(pSharedKey, sizeof(struct rt_cipher_key)); 341 pSharedKey->KeyLen = LEN_TKIP_EK; 342 NdisMoveMemory(pSharedKey->Key, pAd->StaCfg.GTK, LEN_TKIP_EK); 343 NdisMoveMemory(pSharedKey->RxMic, &pAd->StaCfg.GTK[16], 344 LEN_TKIP_RXMICK); 345 NdisMoveMemory(pSharedKey->TxMic, &pAd->StaCfg.GTK[24], 346 LEN_TKIP_TXMICK); 347 348 /* Update Shared Key CipherAlg */ 349 pSharedKey->CipherAlg = CIPHER_NONE; 350 if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) 351 pSharedKey->CipherAlg = CIPHER_TKIP; 352 else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) 353 pSharedKey->CipherAlg = CIPHER_AES; 354 else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) 355 pSharedKey->CipherAlg = CIPHER_WEP64; 356 else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) 357 pSharedKey->CipherAlg = CIPHER_WEP128; 358 359 /* Update group key information to ASIC Shared Key Table */ 360 AsicAddSharedKeyEntry(pAd, 361 BSS0, 362 pAd->StaCfg.DefaultKeyId, 363 pSharedKey->CipherAlg, 364 pSharedKey->Key, 365 pSharedKey->TxMic, pSharedKey->RxMic); 366 367 /* Update ASIC WCID attribute table and IVEIV table */ 368 RTMPAddWcidAttributeEntry(pAd, 369 BSS0, 370 pAd->StaCfg.DefaultKeyId, 371 pSharedKey->CipherAlg, NULL); 372 373} 374