2 *************************************************************************
4 * 5F., No.36, Taiyuan St., Jhubei City,
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
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. *
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. *
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. *
25 *************************************************************************
34 -------- ---------- ----------------------------------------------
35 Jan Lee 03-07-22 Initial
36 Paul Lin 03-11-28 Modify for supplicant
38 #include "../rt_config.h"
40 UCHAR OUI_WPA_NONE_AKM[4] = { 0x00, 0x50, 0xF2, 0x00 };
41 UCHAR OUI_WPA_VERSION[4] = { 0x00, 0x50, 0xF2, 0x01 };
42 UCHAR OUI_WPA_WEP40[4] = { 0x00, 0x50, 0xF2, 0x01 };
43 UCHAR OUI_WPA_TKIP[4] = { 0x00, 0x50, 0xF2, 0x02 };
44 UCHAR OUI_WPA_CCMP[4] = { 0x00, 0x50, 0xF2, 0x04 };
45 UCHAR OUI_WPA_WEP104[4] = { 0x00, 0x50, 0xF2, 0x05 };
46 UCHAR OUI_WPA_8021X_AKM[4] = { 0x00, 0x50, 0xF2, 0x01 };
47 UCHAR OUI_WPA_PSK_AKM[4] = { 0x00, 0x50, 0xF2, 0x02 };
50 UCHAR OUI_WPA2_WEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 };
51 UCHAR OUI_WPA2_TKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 };
52 UCHAR OUI_WPA2_CCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 };
53 UCHAR OUI_WPA2_8021X_AKM[4] = { 0x00, 0x0F, 0xAC, 0x01 };
54 UCHAR OUI_WPA2_PSK_AKM[4] = { 0x00, 0x0F, 0xAC, 0x02 };
55 UCHAR OUI_WPA2_WEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 };
57 static VOID ConstructEapolKeyData(IN PMAC_TABLE_ENTRY pEntry,
58 IN UCHAR GroupKeyWepStatus,
61 IN UCHAR DefaultKeyIdx,
64 IN UCHAR RSNIE_LEN, OUT PEAPOL_PACKET pMsg);
66 static VOID CalculateMIC(IN UCHAR KeyDescVer,
67 IN UCHAR * PTK, OUT PEAPOL_PACKET pMsg);
69 static VOID WpaEAPPacketAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem);
71 static VOID WpaEAPOLASFAlertAction(IN PRTMP_ADAPTER pAd,
72 IN MLME_QUEUE_ELEM * Elem);
74 static VOID WpaEAPOLLogoffAction(IN PRTMP_ADAPTER pAd,
75 IN MLME_QUEUE_ELEM * Elem);
77 static VOID WpaEAPOLStartAction(IN PRTMP_ADAPTER pAd,
78 IN MLME_QUEUE_ELEM * Elem);
80 static VOID WpaEAPOLKeyAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem);
83 ==========================================================================
85 association state machine init, including state transition and timer init
87 S - pointer to the association state machine
88 ==========================================================================
90 VOID WpaStateMachineInit(IN PRTMP_ADAPTER pAd,
91 IN STATE_MACHINE * S, OUT STATE_MACHINE_FUNC Trans[])
93 StateMachineInit(S, (STATE_MACHINE_FUNC *) Trans, MAX_WPA_PTK_STATE,
94 MAX_WPA_MSG, (STATE_MACHINE_FUNC) Drop, WPA_PTK,
97 StateMachineSetAction(S, WPA_PTK, MT2_EAPPacket,
98 (STATE_MACHINE_FUNC) WpaEAPPacketAction);
99 StateMachineSetAction(S, WPA_PTK, MT2_EAPOLStart,
100 (STATE_MACHINE_FUNC) WpaEAPOLStartAction);
101 StateMachineSetAction(S, WPA_PTK, MT2_EAPOLLogoff,
102 (STATE_MACHINE_FUNC) WpaEAPOLLogoffAction);
103 StateMachineSetAction(S, WPA_PTK, MT2_EAPOLKey,
104 (STATE_MACHINE_FUNC) WpaEAPOLKeyAction);
105 StateMachineSetAction(S, WPA_PTK, MT2_EAPOLASFAlert,
106 (STATE_MACHINE_FUNC) WpaEAPOLASFAlertAction);
110 ==========================================================================
112 this is state machine function.
113 When receiving EAP packets which is for 802.1x authentication use.
116 ==========================================================================
118 VOID WpaEAPPacketAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem)
122 VOID WpaEAPOLASFAlertAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem)
126 VOID WpaEAPOLLogoffAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem)
131 ==========================================================================
133 Start 4-way HS when rcv EAPOL_START which may create by our driver in assoc.c
135 ==========================================================================
137 VOID WpaEAPOLStartAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem)
139 MAC_TABLE_ENTRY *pEntry;
140 PHEADER_802_11 pHeader;
142 DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLStartAction ===> \n"));
144 pHeader = (PHEADER_802_11) Elem->Msg;
146 //For normaol PSK, we enqueue an EAPOL-Start command to trigger the process.
147 if (Elem->MsgLen == 6)
148 pEntry = MacTableLookup(pAd, Elem->Msg);
150 pEntry = MacTableLookup(pAd, pHeader->Addr2);
154 DBGPRINT(RT_DEBUG_TRACE,
155 (" PortSecured(%d), WpaState(%d), AuthMode(%d), PMKID_CacheIdx(%d) \n",
156 pEntry->PortSecured, pEntry->WpaState,
157 pEntry->AuthMode, pEntry->PMKID_CacheIdx));
159 if ((pEntry->PortSecured == WPA_802_1X_PORT_NOT_SECURED)
160 && (pEntry->WpaState < AS_PTKSTART)
161 && ((pEntry->AuthMode == Ndis802_11AuthModeWPAPSK)
162 || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)
163 || ((pEntry->AuthMode == Ndis802_11AuthModeWPA2)
164 && (pEntry->PMKID_CacheIdx != ENTRY_NOT_FOUND)))) {
165 pEntry->PrivacyFilter = Ndis802_11PrivFilter8021xWEP;
166 pEntry->WpaState = AS_INITPSK;
167 pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED;
168 NdisZeroMemory(pEntry->R_Counter,
169 sizeof(pEntry->R_Counter));
170 pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR;
172 WPAStart4WayHS(pAd, pEntry, PEER_MSG1_RETRY_EXEC_INTV);
178 ==========================================================================
180 This is state machine function.
181 When receiving EAPOL packets which is for 802.1x key management.
182 Use both in WPA, and WPAPSK case.
183 In this function, further dispatch to different functions according to the received packet. 3 categories are :
184 1. normal 4-way pairwisekey and 2-way groupkey handshake
185 2. MIC error (Countermeasures attack) report packet from STA.
186 3. Request for pairwise/group key update from STA
188 ==========================================================================
190 VOID WpaEAPOLKeyAction(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem)
192 MAC_TABLE_ENTRY *pEntry;
193 PHEADER_802_11 pHeader;
194 PEAPOL_PACKET pEapol_packet;
195 KEY_INFO peerKeyInfo;
197 DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLKeyAction ===>\n"));
199 pHeader = (PHEADER_802_11) Elem->Msg;
201 (PEAPOL_PACKET) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
203 NdisZeroMemory((PUCHAR) & peerKeyInfo, sizeof(peerKeyInfo));
204 NdisMoveMemory((PUCHAR) & peerKeyInfo,
205 (PUCHAR) & pEapol_packet->KeyDesc.KeyInfo,
208 hex_dump("Received Eapol frame", (unsigned char *)pEapol_packet,
209 (Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H));
211 *((USHORT *) & peerKeyInfo) = cpu2le16(*((USHORT *) & peerKeyInfo));
214 pEntry = MacTableLookup(pAd, pHeader->Addr2);
217 || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
220 if (pEntry->AuthMode < Ndis802_11AuthModeWPA)
223 DBGPRINT(RT_DEBUG_TRACE,
224 ("Receive EAPoL-Key frame from STA %02X-%02X-%02X-%02X-%02X-%02X\n",
225 PRINT_MAC(pEntry->Addr)));
227 if (((pEapol_packet->ProVer != EAPOL_VER)
228 && (pEapol_packet->ProVer != EAPOL_VER2))
229 || ((pEapol_packet->KeyDesc.Type != WPA1_KEY_DESC)
230 && (pEapol_packet->KeyDesc.Type != WPA2_KEY_DESC))) {
231 DBGPRINT(RT_DEBUG_ERROR,
232 ("Key descripter does not match with WPA rule\n"));
235 // The value 1 shall be used for all EAPOL-Key frames to and from a STA when
236 // neither the group nor pairwise ciphers are CCMP for Key Descriptor 1.
237 if ((pEntry->WepStatus == Ndis802_11Encryption2Enabled)
238 && (peerKeyInfo.KeyDescVer != DESC_TYPE_TKIP)) {
239 DBGPRINT(RT_DEBUG_ERROR,
240 ("Key descripter version not match(TKIP) \n"));
243 // The value 2 shall be used for all EAPOL-Key frames to and from a STA when
244 // either the pairwise or the group cipher is AES-CCMP for Key Descriptor 2.
245 else if ((pEntry->WepStatus == Ndis802_11Encryption3Enabled)
246 && (peerKeyInfo.KeyDescVer != DESC_TYPE_AES)) {
247 DBGPRINT(RT_DEBUG_ERROR,
248 ("Key descripter version not match(AES) \n"));
251 // Check if this STA is in class 3 state and the WPA state is started
252 if ((pEntry->Sst == SST_ASSOC)
253 && (pEntry->WpaState >= AS_INITPSK)) {
254 // Check the Key Ack (bit 7) of the Key Information to determine the Authenticator
256 // An EAPOL-Key frame that is sent by the Supplicant in response to an EAPOL-
257 // Key frame from the Authenticator must not have the Ack bit set.
258 if (peerKeyInfo.KeyAck == 1) {
259 // The frame is snet by Authenticator.
260 // So the Supplicant side shall handle this.
262 if ((peerKeyInfo.Secure == 0)
263 && (peerKeyInfo.Request == 0)
264 && (peerKeyInfo.Error == 0)
265 && (peerKeyInfo.KeyType == PAIRWISEKEY)) {
266 // Process 1. the message 1 of 4-way HS in WPA or WPA2
267 // EAPOL-Key(0,0,1,0,P,0,0,ANonce,0,DataKD_M1)
268 // 2. the message 3 of 4-way HS in WPA
269 // EAPOL-Key(0,1,1,1,P,0,KeyRSC,ANonce,MIC,DataKD_M3)
270 if (peerKeyInfo.KeyMic == 0)
271 PeerPairMsg1Action(pAd, pEntry,
274 PeerPairMsg3Action(pAd, pEntry,
276 } else if ((peerKeyInfo.Secure == 1)
277 && (peerKeyInfo.KeyMic == 1)
278 && (peerKeyInfo.Request == 0)
279 && (peerKeyInfo.Error == 0)) {
280 // Process 1. the message 3 of 4-way HS in WPA2
281 // EAPOL-Key(1,1,1,1,P,0,KeyRSC,ANonce,MIC,DataKD_M3)
282 // 2. the message 1 of group KS in WPA or WPA2
283 // EAPOL-Key(1,1,1,0,G,0,Key RSC,0, MIC,GTK[N])
284 if (peerKeyInfo.KeyType == PAIRWISEKEY)
285 PeerPairMsg3Action(pAd, pEntry,
288 PeerGroupMsg1Action(pAd, pEntry,
292 // The frame is snet by Supplicant.
293 // So the Authenticator side shall handle this.
294 if ((peerKeyInfo.Request == 0) &&
295 (peerKeyInfo.Error == 0) &&
296 (peerKeyInfo.KeyMic == 1)) {
297 if (peerKeyInfo.Secure == 0
298 && peerKeyInfo.KeyType ==
300 // EAPOL-Key(0,1,0,0,P,0,0,SNonce,MIC,Data)
301 // Process 1. message 2 of 4-way HS in WPA or WPA2
302 // 2. message 4 of 4-way HS in WPA
303 if (CONV_ARRARY_TO_UINT16
304 (pEapol_packet->KeyDesc.
306 PeerPairMsg4Action(pAd,
310 PeerPairMsg2Action(pAd,
314 } else if (peerKeyInfo.Secure == 1
315 && peerKeyInfo.KeyType ==
317 // EAPOL-Key(1,1,0,0,P,0,0,0,MIC,0)
318 // Process message 4 of 4-way HS in WPA2
319 PeerPairMsg4Action(pAd, pEntry,
321 } else if (peerKeyInfo.Secure == 1
322 && peerKeyInfo.KeyType ==
324 // EAPOL-Key(1,1,0,0,G,0,0,0,MIC,0)
325 // Process message 2 of Group key HS in WPA or WPA2
326 PeerGroupMsg2Action(pAd, pEntry,
341 ========================================================================
344 Copy frame from waiting queue into relative ring buffer and set
345 appropriate ASIC register to kick hardware encryption before really
349 pAd Pointer to our adapter
350 PNDIS_PACKET Pointer to outgoing Ndis frame
351 NumberOfFrag Number of fragment required
358 ========================================================================
360 VOID RTMPToWirelessSta(IN PRTMP_ADAPTER pAd,
361 IN PMAC_TABLE_ENTRY pEntry,
362 IN PUCHAR pHeader802_3,
364 IN PUCHAR pData, IN UINT DataLen, IN BOOLEAN bClearFrame)
366 PNDIS_PACKET pPacket;
369 if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
373 // build a NDIS packet
375 RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen,
377 if (Status != NDIS_STATUS_SUCCESS)
381 RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1);
383 RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0);
385 RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS);
387 RTMP_SET_PACKET_NET_DEVICE_MBSSID(pPacket, MAIN_MBSSID); // set a default value
388 if (pEntry->apidx != 0)
389 RTMP_SET_PACKET_NET_DEVICE_MBSSID(pPacket,
393 RTMP_SET_PACKET_WCID(pPacket, (UCHAR) pEntry->Aid);
394 RTMP_SET_PACKET_MOREDATA(pPacket, FALSE);
398 // send out the packet
399 Status = STASendPacket(pAd, pPacket);
400 if (Status == NDIS_STATUS_SUCCESS) {
403 // Dequeue one frame from TxSwQueue0..3 queue and process it
404 // There are three place calling dequeue for TX ring.
405 // 1. Here, right after queueing the frame.
406 // 2. At the end of TxRingTxDone service routine.
407 // 3. Upon NDIS call RTMPSendPackets
409 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
412 (pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))) {
413 for (Index = 0; Index < 5; Index++)
414 if (pAd->TxSwQueue[Index].
416 RTMPDeQueuePacket(pAd,
428 ==========================================================================
430 This is a function to initilize 4-way handshake
434 ==========================================================================
436 VOID WPAStart4WayHS(IN PRTMP_ADAPTER pAd,
437 IN MAC_TABLE_ENTRY * pEntry, IN ULONG TimeInterval)
439 UCHAR Header802_3[14];
440 EAPOL_PACKET EAPOLPKT;
441 PUINT8 pBssid = NULL;
442 UCHAR group_cipher = Ndis802_11WEPDisabled;
444 DBGPRINT(RT_DEBUG_TRACE, ("===> WPAStart4WayHS\n"));
448 fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS))
450 DBGPRINT(RT_DEBUG_ERROR,
451 ("[ERROR]WPAStart4WayHS : The interface is closed...\n"));
455 if (pBssid == NULL) {
456 DBGPRINT(RT_DEBUG_ERROR,
457 ("[ERROR]WPAStart4WayHS : No corresponding Authenticator.\n"));
461 if ((pEntry->WpaState > AS_PTKSTART) || (pEntry->WpaState < AS_INITPMK)) {
462 DBGPRINT(RT_DEBUG_ERROR,
463 ("[ERROR]WPAStart4WayHS : Not expect calling\n"));
467 // Increment replay counter by 1
468 ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
470 // Randomly generate ANonce
471 GenRandom(pAd, (UCHAR *) pBssid, pEntry->ANonce);
473 // Construct EAPoL message - Pairwise Msg 1
474 // EAPOL-Key(0,0,1,0,P,0,0,ANonce,0,DataKD_M1)
475 NdisZeroMemory(&EAPOLPKT, sizeof(EAPOL_PACKET));
476 ConstructEapolMsg(pEntry, group_cipher, EAPOL_PAIR_MSG_1, 0, // Default key index
477 pEntry->ANonce, NULL, // TxRSC
483 // Make outgoing frame
484 MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
485 RTMPToWirelessSta(pAd, pEntry, Header802_3,
486 LENGTH_802_3, (PUCHAR) & EAPOLPKT,
487 CONV_ARRARY_TO_UINT16(EAPOLPKT.Body_Len) + 4,
488 (pEntry->PortSecured ==
489 WPA_802_1X_PORT_SECURED) ? FALSE : TRUE);
491 // Trigger Retry Timer
492 RTMPModTimer(&pEntry->RetryTimer, TimeInterval);
495 pEntry->WpaState = AS_PTKSTART;
497 DBGPRINT(RT_DEBUG_TRACE,
498 ("<=== WPAStart4WayHS: send Msg1 of 4-way \n"));
503 ========================================================================
506 Process Pairwise key Msg-1 of 4-way handshaking and send Msg-2
509 pAd Pointer to our adapter
517 ========================================================================
519 VOID PeerPairMsg1Action(IN PRTMP_ADAPTER pAd,
520 IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem)
523 UCHAR Header802_3[14];
526 EAPOL_PACKET EAPOLPKT;
527 PUINT8 pCurrentAddr = NULL;
528 PUINT8 pmk_ptr = NULL;
529 UCHAR group_cipher = Ndis802_11WEPDisabled;
530 PUINT8 rsnie_ptr = NULL;
533 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg1Action \n"));
535 if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
539 (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
540 sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE - 2))
544 pCurrentAddr = pAd->CurrentAddress;
545 pmk_ptr = pAd->StaCfg.PMK;
546 group_cipher = pAd->StaCfg.GroupCipher;
547 rsnie_ptr = pAd->StaCfg.RSN_IE;
548 rsnie_len = pAd->StaCfg.RSNIE_Len;
551 // Store the received frame
552 pMsg1 = (PEAPOL_PACKET) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
553 MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
555 // Sanity Check peer Pairwise message 1 - Replay Counter
556 if (PeerWpaMessageSanity(pAd, pMsg1, MsgLen, EAPOL_PAIR_MSG_1, pEntry)
560 // Store Replay counter, it will use to verify message 3 and construct message 2
561 NdisMoveMemory(pEntry->R_Counter, pMsg1->KeyDesc.ReplayCounter,
562 LEN_KEY_DESC_REPLAY);
565 NdisMoveMemory(pEntry->ANonce, pMsg1->KeyDesc.KeyNonce,
568 // Generate random SNonce
569 GenRandom(pAd, (UCHAR *) pCurrentAddr, pEntry->SNonce);
572 // Calculate PTK(ANonce, SNonce)
577 pEntry->SNonce, pCurrentAddr, PTK, LEN_PTK);
579 // Save key to PTK entry
580 NdisMoveMemory(pEntry->PTK, PTK, LEN_PTK);
584 pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
586 // Construct EAPoL message - Pairwise Msg 2
587 // EAPOL-Key(0,1,0,0,P,0,0,SNonce,MIC,DataKD_M2)
588 NdisZeroMemory(&EAPOLPKT, sizeof(EAPOL_PACKET));
589 ConstructEapolMsg(pEntry, group_cipher, EAPOL_PAIR_MSG_2, 0, // DefaultKeyIdx
590 pEntry->SNonce, NULL, // TxRsc
592 (UCHAR *) rsnie_ptr, rsnie_len, &EAPOLPKT);
594 // Make outgoing frame
595 MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
597 RTMPToWirelessSta(pAd, pEntry,
598 Header802_3, sizeof(Header802_3), (PUCHAR) & EAPOLPKT,
599 CONV_ARRARY_TO_UINT16(EAPOLPKT.Body_Len) + 4, TRUE);
601 DBGPRINT(RT_DEBUG_TRACE,
602 ("<=== PeerPairMsg1Action: send Msg2 of 4-way \n"));
606 ==========================================================================
608 When receiving the second packet of 4-way pairwisekey handshake.
610 ==========================================================================
612 VOID PeerPairMsg2Action(IN PRTMP_ADAPTER pAd,
613 IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem)
617 PHEADER_802_11 pHeader;
618 EAPOL_PACKET EAPOLPKT;
621 UCHAR Header802_3[LENGTH_802_3];
623 PUINT8 pBssid = NULL;
624 PUINT8 pmk_ptr = NULL;
625 PUINT8 gtk_ptr = NULL;
626 UCHAR default_key = 0;
627 UCHAR group_cipher = Ndis802_11WEPDisabled;
628 PUINT8 rsnie_ptr = NULL;
631 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg2Action \n"));
633 if ((!pEntry) || (!pEntry->ValidAsCLI))
637 (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
638 sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE - 2))
641 // check Entry in valid State
642 if (pEntry->WpaState < AS_PTKSTART)
645 // pointer to 802.11 header
646 pHeader = (PHEADER_802_11) Elem->Msg;
648 // skip 802.11_header(24-byte) and LLC_header(8)
649 pMsg2 = (PEAPOL_PACKET) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
650 MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
653 NdisMoveMemory(pEntry->SNonce, pMsg2->KeyDesc.KeyNonce,
658 WpaDerivePTK(pAd, (UCHAR *) pmk_ptr, pEntry->ANonce, // ANONCE
659 (UCHAR *) pBssid, pEntry->SNonce, // SNONCE
660 pEntry->Addr, PTK, LEN_PTK);
662 NdisMoveMemory(pEntry->PTK, PTK, LEN_PTK);
665 // Sanity Check peer Pairwise message 2 - Replay Counter, MIC, RSNIE
666 if (PeerWpaMessageSanity(pAd, pMsg2, MsgLen, EAPOL_PAIR_MSG_2, pEntry)
671 // delete retry timer
672 RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
675 pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
677 // Increment replay counter by 1
678 ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
680 // Construct EAPoL message - Pairwise Msg 3
681 NdisZeroMemory(&EAPOLPKT, sizeof(EAPOL_PACKET));
682 ConstructEapolMsg(pEntry,
689 (UCHAR *) rsnie_ptr, rsnie_len, &EAPOLPKT);
691 // Make outgoing frame
692 MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
693 RTMPToWirelessSta(pAd, pEntry, Header802_3, LENGTH_802_3,
695 CONV_ARRARY_TO_UINT16(EAPOLPKT.Body_Len) + 4,
696 (pEntry->PortSecured ==
697 WPA_802_1X_PORT_SECURED) ? FALSE : TRUE);
699 pEntry->ReTryCounter = PEER_MSG3_RETRY_TIMER_CTR;
700 RTMPSetTimer(&pEntry->RetryTimer, PEER_MSG3_RETRY_EXEC_INTV);
703 pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
706 DBGPRINT(RT_DEBUG_TRACE,
707 ("<=== PeerPairMsg2Action: send Msg3 of 4-way \n"));
711 ========================================================================
714 Process Pairwise key Msg 3 of 4-way handshaking and send Msg 4
717 pAd Pointer to our adapter
725 ========================================================================
727 VOID PeerPairMsg3Action(IN PRTMP_ADAPTER pAd,
728 IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem)
730 PHEADER_802_11 pHeader;
731 UCHAR Header802_3[14];
732 EAPOL_PACKET EAPOLPKT;
735 PUINT8 pCurrentAddr = NULL;
736 UCHAR group_cipher = Ndis802_11WEPDisabled;
738 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg3Action \n"));
740 if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
744 (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
745 sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE - 2))
749 pCurrentAddr = pAd->CurrentAddress;
750 group_cipher = pAd->StaCfg.GroupCipher;
754 // Record 802.11 header & the received EAPOL packet Msg3
755 pHeader = (PHEADER_802_11) Elem->Msg;
756 pMsg3 = (PEAPOL_PACKET) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
757 MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
759 // Sanity Check peer Pairwise message 3 - Replay Counter, MIC, RSNIE
760 if (PeerWpaMessageSanity(pAd, pMsg3, MsgLen, EAPOL_PAIR_MSG_3, pEntry)
764 // Save Replay counter, it will use construct message 4
765 NdisMoveMemory(pEntry->R_Counter, pMsg3->KeyDesc.ReplayCounter,
766 LEN_KEY_DESC_REPLAY);
768 // Double check ANonce
770 (pEntry->ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) {
773 // Construct EAPoL message - Pairwise Msg 4
774 NdisZeroMemory(&EAPOLPKT, sizeof(EAPOL_PACKET));
775 ConstructEapolMsg(pEntry, group_cipher, EAPOL_PAIR_MSG_4, 0, // group key index not used in message 4
776 NULL, // Nonce not used in message 4
777 NULL, // TxRSC not used in message 4
778 NULL, // GTK not used in message 4
779 NULL, // RSN IE not used in message 4
783 pEntry->WpaState = AS_PTKINITDONE;
785 // Update pairwise key
787 PCIPHER_KEY pSharedKey;
789 pSharedKey = &pAd->SharedKey[BSS0][0];
791 NdisMoveMemory(pAd->StaCfg.PTK, pEntry->PTK, LEN_PTK);
793 // Prepare pair-wise key information into shared key table
794 NdisZeroMemory(pSharedKey, sizeof(CIPHER_KEY));
795 pSharedKey->KeyLen = LEN_TKIP_EK;
796 NdisMoveMemory(pSharedKey->Key, &pAd->StaCfg.PTK[32],
798 NdisMoveMemory(pSharedKey->RxMic, &pAd->StaCfg.PTK[48],
800 NdisMoveMemory(pSharedKey->TxMic,
801 &pAd->StaCfg.PTK[48 + LEN_TKIP_RXMICK],
804 // Decide its ChiperAlg
805 if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled)
806 pSharedKey->CipherAlg = CIPHER_TKIP;
807 else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled)
808 pSharedKey->CipherAlg = CIPHER_AES;
810 pSharedKey->CipherAlg = CIPHER_NONE;
812 // Update these related information to MAC_TABLE_ENTRY
813 pEntry = &pAd->MacTab.Content[BSSID_WCID];
814 NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32],
816 NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48],
818 NdisMoveMemory(pEntry->PairwiseKey.TxMic,
819 &pAd->StaCfg.PTK[48 + LEN_TKIP_RXMICK],
821 pEntry->PairwiseKey.CipherAlg = pSharedKey->CipherAlg;
823 // Update pairwise key information to ASIC Shared Key Table
824 AsicAddSharedKeyEntry(pAd,
827 pSharedKey->CipherAlg,
829 pSharedKey->TxMic, pSharedKey->RxMic);
831 // Update ASIC WCID attribute table and IVEIV table
832 RTMPAddWcidAttributeEntry(pAd,
834 0, pSharedKey->CipherAlg, pEntry);
838 // open 802.1x port control and privacy filter
839 if (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK ||
840 pEntry->AuthMode == Ndis802_11AuthModeWPA2) {
841 pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
842 pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
844 STA_PORT_SECURED(pAd);
845 // Indicate Connected for GUI
846 pAd->IndicateMediaState = NdisMediaStateConnected;
847 DBGPRINT(RT_DEBUG_TRACE,
848 ("PeerPairMsg3Action: AuthMode(%s) PairwiseCipher(%s) GroupCipher(%s) \n",
849 GetAuthMode(pEntry->AuthMode),
850 GetEncryptType(pEntry->WepStatus),
851 GetEncryptType(group_cipher)));
855 // Init 802.3 header and send out
856 MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
857 RTMPToWirelessSta(pAd, pEntry,
858 Header802_3, sizeof(Header802_3),
860 CONV_ARRARY_TO_UINT16(EAPOLPKT.Body_Len) + 4, TRUE);
862 DBGPRINT(RT_DEBUG_TRACE,
863 ("<=== PeerPairMsg3Action: send Msg4 of 4-way \n"));
867 ==========================================================================
869 When receiving the last packet of 4-way pairwisekey handshake.
870 Initilize 2-way groupkey handshake following.
872 ==========================================================================
874 VOID PeerPairMsg4Action(IN PRTMP_ADAPTER pAd,
875 IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem)
878 PHEADER_802_11 pHeader;
881 UCHAR group_cipher = Ndis802_11WEPDisabled;
883 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg4Action\n"));
886 if ((!pEntry) || (!pEntry->ValidAsCLI))
890 (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
891 sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE - 2))
894 if (pEntry->WpaState < AS_PTKINIT_NEGOTIATING)
897 // pointer to 802.11 header
898 pHeader = (PHEADER_802_11) Elem->Msg;
900 // skip 802.11_header(24-byte) and LLC_header(8)
902 (PEAPOL_PACKET) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
903 MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
905 // Sanity Check peer Pairwise message 4 - Replay Counter, MIC
906 if (PeerWpaMessageSanity
907 (pAd, pMsg4, MsgLen, EAPOL_PAIR_MSG_4, pEntry) == FALSE)
910 // 3. uses the MLME.SETKEYS.request to configure PTK into MAC
911 NdisZeroMemory(&pEntry->PairwiseKey, sizeof(CIPHER_KEY));
913 // reset IVEIV in Asic
914 AsicUpdateWCIDIVEIV(pAd, pEntry->Aid, 1, 0);
916 pEntry->PairwiseKey.KeyLen = LEN_TKIP_EK;
917 NdisMoveMemory(pEntry->PairwiseKey.Key, &pEntry->PTK[32],
919 NdisMoveMemory(pEntry->PairwiseKey.RxMic,
920 &pEntry->PTK[TKIP_AP_RXMICK_OFFSET],
922 NdisMoveMemory(pEntry->PairwiseKey.TxMic,
923 &pEntry->PTK[TKIP_AP_TXMICK_OFFSET],
926 // Set pairwise key to Asic
928 pEntry->PairwiseKey.CipherAlg = CIPHER_NONE;
929 if (pEntry->WepStatus == Ndis802_11Encryption2Enabled)
930 pEntry->PairwiseKey.CipherAlg = CIPHER_TKIP;
931 else if (pEntry->WepStatus ==
932 Ndis802_11Encryption3Enabled)
933 pEntry->PairwiseKey.CipherAlg = CIPHER_AES;
935 // Add Pair-wise key to Asic
936 AsicAddPairwiseKeyEntry(pAd,
939 &pEntry->PairwiseKey);
941 // update WCID attribute table and IVEIV table for this entry
942 RTMPAddWcidAttributeEntry(pAd,
945 pEntry->PairwiseKey.CipherAlg,
950 pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
951 pEntry->WpaState = AS_PTKINITDONE;
952 pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
954 if (pEntry->AuthMode == Ndis802_11AuthModeWPA2 ||
955 pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) {
956 pEntry->GTKState = REKEY_ESTABLISHED;
957 RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
959 // send wireless event - for set key done WPA2
960 if (pAd->CommonCfg.bWirelessEvent)
961 RTMPSendWirelessEvent(pAd,
962 IW_SET_KEY_DONE_WPA2_EVENT_FLAG,
966 DBGPRINT(RT_DEBUG_OFF,
967 ("AP SETKEYS DONE - WPA2, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
969 GetAuthMode(pEntry->AuthMode),
971 GetEncryptType(pEntry->WepStatus),
972 group_cipher, GetEncryptType(group_cipher)));
974 // 5. init Group 2-way handshake if necessary.
975 WPAStart2WayGroupHS(pAd, pEntry);
977 pEntry->ReTryCounter = GROUP_MSG1_RETRY_TIMER_CTR;
978 RTMPModTimer(&pEntry->RetryTimer,
979 PEER_MSG3_RETRY_EXEC_INTV);
986 ==========================================================================
988 This is a function to send the first packet of 2-way groupkey handshake
991 ==========================================================================
993 VOID WPAStart2WayGroupHS(IN PRTMP_ADAPTER pAd, IN MAC_TABLE_ENTRY * pEntry)
995 UCHAR Header802_3[14];
997 EAPOL_PACKET EAPOLPKT;
998 UCHAR group_cipher = Ndis802_11WEPDisabled;
999 UCHAR default_key = 0;
1000 PUINT8 gnonce_ptr = NULL;
1001 PUINT8 gtk_ptr = NULL;
1002 PUINT8 pBssid = NULL;
1004 DBGPRINT(RT_DEBUG_TRACE, ("===> WPAStart2WayGroupHS\n"));
1006 if ((!pEntry) || (!pEntry->ValidAsCLI))
1010 // Increment replay counter by 1
1011 ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
1013 // Construct EAPoL message - Group Msg 1
1014 NdisZeroMemory(&EAPOLPKT, sizeof(EAPOL_PACKET));
1015 ConstructEapolMsg(pEntry,
1019 (UCHAR *) gnonce_ptr,
1020 TxTsc, (UCHAR *) gtk_ptr, NULL, 0, &EAPOLPKT);
1022 // Make outgoing frame
1023 MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pBssid, EAPOL);
1024 RTMPToWirelessSta(pAd, pEntry,
1025 Header802_3, LENGTH_802_3,
1026 (PUCHAR) & EAPOLPKT,
1027 CONV_ARRARY_TO_UINT16(EAPOLPKT.Body_Len) + 4,
1032 DBGPRINT(RT_DEBUG_TRACE,
1033 ("<=== WPAStart2WayGroupHS : send out Group Message 1 \n"));
1039 ========================================================================
1041 Routine Description:
1042 Process Group key 2-way handshaking
1045 pAd Pointer to our adapter
1053 ========================================================================
1055 VOID PeerGroupMsg1Action(IN PRTMP_ADAPTER pAd,
1056 IN MAC_TABLE_ENTRY * pEntry, IN MLME_QUEUE_ELEM * Elem)
1058 UCHAR Header802_3[14];
1059 EAPOL_PACKET EAPOLPKT;
1060 PEAPOL_PACKET pGroup;
1063 UCHAR default_key = 0;
1064 UCHAR group_cipher = Ndis802_11WEPDisabled;
1065 PUINT8 pCurrentAddr = NULL;
1067 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerGroupMsg1Action \n"));
1069 if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
1073 pCurrentAddr = pAd->CurrentAddress;
1074 group_cipher = pAd->StaCfg.GroupCipher;
1075 default_key = pAd->StaCfg.DefaultKeyId;
1078 // Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8)
1079 pGroup = (PEAPOL_PACKET) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
1080 MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
1082 // Sanity Check peer group message 1 - Replay Counter, MIC, RSNIE
1083 if (PeerWpaMessageSanity(pAd, pGroup, MsgLen, EAPOL_GROUP_MSG_1, pEntry)
1087 // delete retry timer
1088 RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
1090 // Save Replay counter, it will use to construct message 2
1091 NdisMoveMemory(pEntry->R_Counter, pGroup->KeyDesc.ReplayCounter,
1092 LEN_KEY_DESC_REPLAY);
1094 // Construct EAPoL message - Group Msg 2
1095 NdisZeroMemory(&EAPOLPKT, sizeof(EAPOL_PACKET));
1096 ConstructEapolMsg(pEntry, group_cipher, EAPOL_GROUP_MSG_2, default_key, NULL, // Nonce not used
1097 NULL, // TxRSC not used
1098 NULL, // GTK not used
1099 NULL, // RSN IE not used
1102 // open 802.1x port control and privacy filter
1103 pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
1104 pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
1106 STA_PORT_SECURED(pAd);
1107 // Indicate Connected for GUI
1108 pAd->IndicateMediaState = NdisMediaStateConnected;
1110 DBGPRINT(RT_DEBUG_TRACE,
1111 ("PeerGroupMsg1Action: AuthMode(%s) PairwiseCipher(%s) GroupCipher(%s) \n",
1112 GetAuthMode(pEntry->AuthMode),
1113 GetEncryptType(pEntry->WepStatus),
1114 GetEncryptType(group_cipher)));
1116 // init header and Fill Packet and send Msg 2 to authenticator
1117 MAKE_802_3_HEADER(Header802_3, pEntry->Addr, pCurrentAddr, EAPOL);
1118 RTMPToWirelessSta(pAd, pEntry,
1119 Header802_3, sizeof(Header802_3),
1120 (PUCHAR) & EAPOLPKT,
1121 CONV_ARRARY_TO_UINT16(EAPOLPKT.Body_Len) + 4, FALSE);
1123 DBGPRINT(RT_DEBUG_TRACE,
1124 ("<=== PeerGroupMsg1Action: sned group message 2\n"));
1128 ==========================================================================
1130 When receiving the last packet of 2-way groupkey handshake.
1132 ==========================================================================
1134 VOID PeerGroupMsg2Action(IN PRTMP_ADAPTER pAd,
1135 IN MAC_TABLE_ENTRY * pEntry,
1136 IN VOID * Msg, IN UINT MsgLen)
1141 PEAPOL_PACKET pMsg2;
1142 UCHAR group_cipher = Ndis802_11WEPDisabled;
1144 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerGroupMsg2Action \n"));
1147 if ((!pEntry) || (!pEntry->ValidAsCLI))
1151 (LENGTH_802_1_H + LENGTH_EAPOL_H + sizeof(KEY_DESCRIPTER) -
1152 MAX_LEN_OF_RSNIE - 2))
1155 if (pEntry->WpaState != AS_PTKINITDONE)
1158 pData = (PUCHAR) Msg;
1159 pMsg2 = (PEAPOL_PACKET) (pData + LENGTH_802_1_H);
1160 Len = MsgLen - LENGTH_802_1_H;
1162 // Sanity Check peer group message 2 - Replay Counter, MIC
1163 if (PeerWpaMessageSanity
1164 (pAd, pMsg2, Len, EAPOL_GROUP_MSG_2, pEntry) == FALSE)
1169 RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
1170 pEntry->GTKState = REKEY_ESTABLISHED;
1172 if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2)
1173 || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) {
1174 // send wireless event - for set key done WPA2
1175 if (pAd->CommonCfg.bWirelessEvent)
1176 RTMPSendWirelessEvent(pAd,
1177 IW_SET_KEY_DONE_WPA2_EVENT_FLAG,
1181 DBGPRINT(RT_DEBUG_OFF,
1182 ("AP SETKEYS DONE - WPA2, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
1184 GetAuthMode(pEntry->AuthMode),
1186 GetEncryptType(pEntry->WepStatus),
1187 group_cipher, GetEncryptType(group_cipher)));
1189 // send wireless event - for set key done WPA
1190 if (pAd->CommonCfg.bWirelessEvent)
1191 RTMPSendWirelessEvent(pAd,
1192 IW_SET_KEY_DONE_WPA1_EVENT_FLAG,
1196 DBGPRINT(RT_DEBUG_OFF,
1197 ("AP SETKEYS DONE - WPA1, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
1199 GetAuthMode(pEntry->AuthMode),
1201 GetEncryptType(pEntry->WepStatus),
1202 group_cipher, GetEncryptType(group_cipher)));
1208 ========================================================================
1210 Routine Description:
1211 Classify WPA EAP message type
1214 EAPType Value of EAP message type
1215 MsgType Internal Message definition for MLME state machine
1218 TRUE Found appropriate message type
1219 FALSE No appropriate message type
1221 IRQL = DISPATCH_LEVEL
1224 All these constants are defined in wpa.h
1225 For supplicant, there is only EAPOL Key message avaliable
1227 ========================================================================
1229 BOOLEAN WpaMsgTypeSubst(IN UCHAR EAPType, OUT INT * MsgType)
1233 *MsgType = MT2_EAPPacket;
1236 *MsgType = MT2_EAPOLStart;
1239 *MsgType = MT2_EAPOLLogoff;
1242 *MsgType = MT2_EAPOLKey;
1245 *MsgType = MT2_EAPOLASFAlert;
1254 ========================================================================
1256 Routine Description:
1257 The pseudo-random function(PRF) that hashes various inputs to
1258 derive a pseudo-random value. To add liveness to the pseudo-random
1259 value, a nonce should be one of the inputs.
1261 It is used to generate PTK, GTK or some specific random value.
1264 UCHAR *key, - the key material for HMAC_SHA1 use
1265 INT key_len - the length of key
1266 UCHAR *prefix - a prefix label
1267 INT prefix_len - the length of the label
1268 UCHAR *data - a specific data with variable length
1269 INT data_len - the length of a specific data
1270 INT len - the output lenght
1273 UCHAR *output - the calculated result
1276 802.11i-2004 Annex H.3
1278 ========================================================================
1280 VOID PRF(IN UCHAR * key,
1284 IN UCHAR * data, IN INT data_len, OUT UCHAR * output, IN INT len)
1288 INT currentindex = 0;
1291 // Allocate memory for input
1292 os_alloc_mem(NULL, (PUCHAR *) & input, 1024);
1294 if (input == NULL) {
1295 DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n"));
1298 // Generate concatenation input
1299 NdisMoveMemory(input, prefix, prefix_len);
1301 // Concatenate a single octet containing 0
1302 input[prefix_len] = 0;
1304 // Concatenate specific data
1305 NdisMoveMemory(&input[prefix_len + 1], data, data_len);
1306 total_len = prefix_len + 1 + data_len;
1308 // Concatenate a single octet containing 0
1309 // This octet shall be update later
1310 input[total_len] = 0;
1313 // Iterate to calculate the result by hmac-sha-1
1314 // Then concatenate to last result
1315 for (i = 0; i < (len + 19) / 20; i++) {
1316 HMAC_SHA1(key, key_len, input, total_len, &output[currentindex],
1320 // update the last octet
1321 input[total_len - 1]++;
1323 os_free_mem(NULL, input);
1327 * F(P, S, c, i) = U1 xor U2 xor ... Uc
1328 * U1 = PRF(P, S || Int(i))
1333 static void F(char *password, unsigned char *ssid, int ssidlength,
1334 int iterations, int count, unsigned char *output)
1336 unsigned char digest[36], digest1[SHA1_DIGEST_SIZE];
1339 /* U1 = PRF(P, S || int(i)) */
1340 memcpy(digest, ssid, ssidlength);
1341 digest[ssidlength] = (unsigned char)((count >> 24) & 0xff);
1342 digest[ssidlength + 1] = (unsigned char)((count >> 16) & 0xff);
1343 digest[ssidlength + 2] = (unsigned char)((count >> 8) & 0xff);
1344 digest[ssidlength + 3] = (unsigned char)(count & 0xff);
1345 HMAC_SHA1((unsigned char *)password, (int)strlen(password), digest, ssidlength + 4, digest1, SHA1_DIGEST_SIZE); // for WPA update
1348 memcpy(output, digest1, SHA1_DIGEST_SIZE);
1350 for (i = 1; i < iterations; i++) {
1351 /* Un = PRF(P, Un-1) */
1352 HMAC_SHA1((unsigned char *)password, (int)strlen(password), digest1, SHA1_DIGEST_SIZE, digest, SHA1_DIGEST_SIZE); // for WPA update
1353 memcpy(digest1, digest, SHA1_DIGEST_SIZE);
1355 /* output = output xor Un */
1356 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
1357 output[j] ^= digest[j];
1363 * password - ascii string up to 63 characters in length
1364 * ssid - octet string up to 32 octets
1365 * ssidlength - length of ssid in octets
1366 * output must be 40 octets in length and outputs 256 bits of key
1368 int PasswordHash(PSTRING password, PUCHAR ssid, INT ssidlength, PUCHAR output)
1370 if ((strlen(password) > 63) || (ssidlength > 32))
1373 F(password, ssid, ssidlength, 4096, 1, output);
1374 F(password, ssid, ssidlength, 4096, 2, &output[SHA1_DIGEST_SIZE]);
1379 ========================================================================
1381 Routine Description:
1382 It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK.
1383 It shall be called by 4-way handshake processing.
1386 pAd - pointer to our pAdapter context
1387 PMK - pointer to PMK
1388 ANonce - pointer to ANonce
1389 AA - pointer to Authenticator Address
1390 SNonce - pointer to SNonce
1391 SA - pointer to Supplicant Address
1392 len - indicate the length of PTK (octet)
1395 Output pointer to the PTK
1398 Refer to IEEE 802.11i-2004 8.5.1.2
1400 ========================================================================
1402 VOID WpaDerivePTK(IN PRTMP_ADAPTER pAd,
1407 IN UCHAR * SA, OUT UCHAR * output, IN UINT len)
1409 UCHAR concatenation[76];
1413 { 'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ',
1414 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'
1417 // initiate the concatenation input
1418 NdisZeroMemory(temp, sizeof(temp));
1419 NdisZeroMemory(concatenation, 76);
1421 // Get smaller address
1422 if (RTMPCompareMemory(SA, AA, 6) == 1)
1423 NdisMoveMemory(concatenation, AA, 6);
1425 NdisMoveMemory(concatenation, SA, 6);
1428 // Get larger address
1429 if (RTMPCompareMemory(SA, AA, 6) == 1)
1430 NdisMoveMemory(&concatenation[CurrPos], SA, 6);
1432 NdisMoveMemory(&concatenation[CurrPos], AA, 6);
1434 // store the larger mac address for backward compatible of
1435 // ralink proprietary STA-key issue
1436 NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN);
1439 // Get smaller Nonce
1440 if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
1441 NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue
1442 else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
1443 NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
1445 NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
1449 if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
1450 NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue
1451 else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
1452 NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
1454 NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
1457 hex_dump("concatenation=", concatenation, 76);
1459 // Use PRF to generate PTK
1460 PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len);
1465 ========================================================================
1467 Routine Description:
1468 Generate random number by software.
1471 pAd - pointer to our pAdapter context
1472 macAddr - pointer to local MAC address
1477 802.1ii-2004 Annex H.5
1479 ========================================================================
1481 VOID GenRandom(IN PRTMP_ADAPTER pAd, IN UCHAR * macAddr, OUT UCHAR * random)
1484 UCHAR local[80], KeyCounter[32];
1488 { 'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r' };
1490 // Zero the related information
1491 NdisZeroMemory(result, 80);
1492 NdisZeroMemory(local, 80);
1493 NdisZeroMemory(KeyCounter, 32);
1495 for (i = 0; i < 32; i++) {
1496 // copy the local MAC address
1497 COPY_MAC_ADDR(local, macAddr);
1498 curr = MAC_ADDR_LEN;
1500 // concatenate the current time
1501 NdisGetSystemUpTime(&CurrentTime);
1502 NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime));
1503 curr += sizeof(CurrentTime);
1505 // concatenate the last result
1506 NdisMoveMemory(&local[curr], result, 32);
1509 // concatenate a variable
1510 NdisMoveMemory(&local[curr], &i, 2);
1513 // calculate the result
1514 PRF(KeyCounter, 32, prefix, 12, local, curr, result, 32);
1517 NdisMoveMemory(random, result, 32);
1521 ========================================================================
1523 Routine Description:
1524 Build cipher suite in RSN-IE.
1525 It only shall be called by RTMPMakeRSNIE.
1528 pAd - pointer to our pAdapter context
1529 ElementID - indicate the WPA1 or WPA2
1530 WepStatus - indicate the encryption type
1531 bMixCipher - a boolean to indicate the pairwise cipher and group
1532 cipher are the same or not
1538 ========================================================================
1540 static VOID RTMPMakeRsnIeCipher(IN PRTMP_ADAPTER pAd,
1543 IN BOOLEAN bMixCipher,
1544 IN UCHAR FlexibleCipher,
1545 OUT PUCHAR pRsnIe, OUT UCHAR * rsn_len)
1551 // decide WPA2 or WPA1
1552 if (ElementID == Wpa2Ie) {
1553 RSNIE2 *pRsnie_cipher = (RSNIE2 *) pRsnIe;
1555 // Assign the verson as 1
1556 pRsnie_cipher->version = 1;
1558 switch (WepStatus) {
1560 case Ndis802_11Encryption2Enabled:
1561 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
1562 pRsnie_cipher->ucount = 1;
1563 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1565 *rsn_len = sizeof(RSNIE2);
1569 case Ndis802_11Encryption3Enabled:
1571 NdisMoveMemory(pRsnie_cipher->mcast,
1574 NdisMoveMemory(pRsnie_cipher->mcast,
1576 pRsnie_cipher->ucount = 1;
1577 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1579 *rsn_len = sizeof(RSNIE2);
1582 // TKIP-AES mix mode
1583 case Ndis802_11Encryption4Enabled:
1584 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
1587 // Insert WPA2 TKIP as the first pairwise cipher
1588 if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) {
1589 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1591 // Insert WPA2 AES as the secondary pairwise cipher
1592 if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) {
1593 NdisMoveMemory(pRsnie_cipher->ucast[0].
1594 oui + 4, OUI_WPA2_CCMP,
1599 // Insert WPA2 AES as the first pairwise cipher
1600 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1604 pRsnie_cipher->ucount = PairwiseCnt;
1605 *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1));
1609 if ((pAd->OpMode == OPMODE_STA) &&
1610 (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) &&
1611 (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) {
1612 UINT GroupCipher = pAd->StaCfg.GroupCipher;
1613 switch (GroupCipher) {
1614 case Ndis802_11GroupWEP40Enabled:
1615 NdisMoveMemory(pRsnie_cipher->mcast,
1618 case Ndis802_11GroupWEP104Enabled:
1619 NdisMoveMemory(pRsnie_cipher->mcast,
1620 OUI_WPA2_WEP104, 4);
1624 // swap for big-endian platform
1625 pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
1626 pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
1628 RSNIE *pRsnie_cipher = (RSNIE *) pRsnIe;
1630 // Assign OUI and version
1631 NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4);
1632 pRsnie_cipher->version = 1;
1634 switch (WepStatus) {
1636 case Ndis802_11Encryption2Enabled:
1637 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
1638 pRsnie_cipher->ucount = 1;
1639 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1641 *rsn_len = sizeof(RSNIE);
1645 case Ndis802_11Encryption3Enabled:
1647 NdisMoveMemory(pRsnie_cipher->mcast,
1650 NdisMoveMemory(pRsnie_cipher->mcast,
1652 pRsnie_cipher->ucount = 1;
1653 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1655 *rsn_len = sizeof(RSNIE);
1658 // TKIP-AES mix mode
1659 case Ndis802_11Encryption4Enabled:
1660 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
1663 // Insert WPA TKIP as the first pairwise cipher
1664 if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) {
1665 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1667 // Insert WPA AES as the secondary pairwise cipher
1668 if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) {
1669 NdisMoveMemory(pRsnie_cipher->ucast[0].
1670 oui + 4, OUI_WPA_CCMP,
1675 // Insert WPA AES as the first pairwise cipher
1676 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1680 pRsnie_cipher->ucount = PairwiseCnt;
1681 *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1));
1685 if ((pAd->OpMode == OPMODE_STA) &&
1686 (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) &&
1687 (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) {
1688 UINT GroupCipher = pAd->StaCfg.GroupCipher;
1689 switch (GroupCipher) {
1690 case Ndis802_11GroupWEP40Enabled:
1691 NdisMoveMemory(pRsnie_cipher->mcast,
1694 case Ndis802_11GroupWEP104Enabled:
1695 NdisMoveMemory(pRsnie_cipher->mcast,
1700 // swap for big-endian platform
1701 pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
1702 pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
1707 ========================================================================
1709 Routine Description:
1710 Build AKM suite in RSN-IE.
1711 It only shall be called by RTMPMakeRSNIE.
1714 pAd - pointer to our pAdapter context
1715 ElementID - indicate the WPA1 or WPA2
1716 AuthMode - indicate the authentication mode
1717 apidx - indicate the interface index
1723 ========================================================================
1725 static VOID RTMPMakeRsnIeAKM(IN PRTMP_ADAPTER pAd,
1729 OUT PUCHAR pRsnIe, OUT UCHAR * rsn_len)
1731 RSNIE_AUTH *pRsnie_auth;
1732 UCHAR AkmCnt = 1; // default as 1
1734 pRsnie_auth = (RSNIE_AUTH *) (pRsnIe + (*rsn_len));
1736 // decide WPA2 or WPA1
1737 if (ElementID == Wpa2Ie) {
1740 case Ndis802_11AuthModeWPA2:
1741 case Ndis802_11AuthModeWPA1WPA2:
1742 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1743 OUI_WPA2_8021X_AKM, 4);
1746 case Ndis802_11AuthModeWPA2PSK:
1747 case Ndis802_11AuthModeWPA1PSKWPA2PSK:
1748 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1749 OUI_WPA2_PSK_AKM, 4);
1758 case Ndis802_11AuthModeWPA:
1759 case Ndis802_11AuthModeWPA1WPA2:
1760 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1761 OUI_WPA_8021X_AKM, 4);
1764 case Ndis802_11AuthModeWPAPSK:
1765 case Ndis802_11AuthModeWPA1PSKWPA2PSK:
1766 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1767 OUI_WPA_PSK_AKM, 4);
1770 case Ndis802_11AuthModeWPANone:
1771 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1772 OUI_WPA_NONE_AKM, 4);
1780 pRsnie_auth->acount = AkmCnt;
1781 pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount);
1783 // update current RSNIE length
1784 (*rsn_len) += (sizeof(RSNIE_AUTH) + (4 * (AkmCnt - 1)));
1789 ========================================================================
1791 Routine Description:
1792 Build capability in RSN-IE.
1793 It only shall be called by RTMPMakeRSNIE.
1796 pAd - pointer to our pAdapter context
1797 ElementID - indicate the WPA1 or WPA2
1798 apidx - indicate the interface index
1804 ========================================================================
1806 static VOID RTMPMakeRsnIeCap(IN PRTMP_ADAPTER pAd,
1809 OUT PUCHAR pRsnIe, OUT UCHAR * rsn_len)
1811 RSN_CAPABILITIES *pRSN_Cap;
1813 // it could be ignored in WPA1 mode
1814 if (ElementID == WpaIe)
1817 pRSN_Cap = (RSN_CAPABILITIES *) (pRsnIe + (*rsn_len));
1819 pRSN_Cap->word = cpu2le16(pRSN_Cap->word);
1821 (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length
1826 ========================================================================
1828 Routine Description:
1829 Build RSN IE context. It is not included element-ID and length.
1832 pAd - pointer to our pAdapter context
1833 AuthMode - indicate the authentication mode
1834 WepStatus - indicate the encryption type
1835 apidx - indicate the interface index
1841 ========================================================================
1843 VOID RTMPMakeRSNIE(IN PRTMP_ADAPTER pAd,
1844 IN UINT AuthMode, IN UINT WepStatus, IN UCHAR apidx)
1846 PUCHAR pRsnIe = NULL; // primary RSNIE
1847 UCHAR *rsnielen_cur_p = 0; // the length of the primary RSNIE
1848 UCHAR *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE
1850 BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different
1852 WPA_MIX_PAIR_CIPHER FlexibleCipher = WPA_TKIPAES_WPA2_TKIPAES; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode
1854 rsnielen_cur_p = NULL;
1855 rsnielen_ex_cur_p = NULL;
1859 if (pAd->StaCfg.WpaSupplicantUP !=
1860 WPA_SUPPLICANT_DISABLE) {
1861 if (AuthMode < Ndis802_11AuthModeWPA)
1864 // Support WPAPSK or WPA2PSK in STA-Infra mode
1865 // Support WPANone in STA-Adhoc mode
1866 if ((AuthMode != Ndis802_11AuthModeWPAPSK) &&
1867 (AuthMode != Ndis802_11AuthModeWPA2PSK) &&
1868 (AuthMode != Ndis802_11AuthModeWPANone)
1873 DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPMakeRSNIE(STA)\n"));
1875 // Zero RSNIE context
1876 pAd->StaCfg.RSNIE_Len = 0;
1877 NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE);
1880 rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len;
1881 pRsnIe = pAd->StaCfg.RSN_IE;
1883 bMixCipher = pAd->StaCfg.bMixCipher;
1887 // indicate primary RSNIE as WPA or WPA2
1888 if ((AuthMode == Ndis802_11AuthModeWPA) ||
1889 (AuthMode == Ndis802_11AuthModeWPAPSK) ||
1890 (AuthMode == Ndis802_11AuthModeWPANone) ||
1891 (AuthMode == Ndis802_11AuthModeWPA1WPA2) ||
1892 (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK))
1893 PrimaryRsnie = WpaIe;
1895 PrimaryRsnie = Wpa2Ie;
1898 // Build the primary RSNIE
1899 // 1. insert cipher suite
1900 RTMPMakeRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher,
1901 FlexibleCipher, pRsnIe, &p_offset);
1904 RTMPMakeRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe,
1907 // 3. insert capability
1908 RTMPMakeRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset);
1911 // 4. update the RSNIE length
1912 *rsnielen_cur_p = p_offset;
1914 hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p));
1919 ==========================================================================
1921 Check whether the received frame is EAP frame.
1924 pAd - pointer to our pAdapter context
1925 pEntry - pointer to active entry
1926 pData - the received frame
1927 DataByteCount - the received frame's length
1928 FromWhichBSSID - indicate the interface index
1931 TRUE - This frame is EAP frame
1933 ==========================================================================
1935 BOOLEAN RTMPCheckWPAframe(IN PRTMP_ADAPTER pAd,
1936 IN PMAC_TABLE_ENTRY pEntry,
1938 IN ULONG DataByteCount, IN UCHAR FromWhichBSSID)
1943 if (DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H))
1947 if (NdisEqualMemory(SNAP_802_1H, pData, 6) ||
1948 // Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL
1949 NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6)) {
1952 // Skip 2-bytes EAPoL type
1953 if (NdisEqualMemory(EAPOL, pData, 2)) {
1958 switch (*(pData + 1)) {
1960 Body_len = (*(pData + 2) << 8) | (*(pData + 3));
1961 DBGPRINT(RT_DEBUG_TRACE,
1962 ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n",
1966 DBGPRINT(RT_DEBUG_TRACE,
1967 ("Receive EAPOL-Start frame, TYPE = 1 \n"));
1968 if (pEntry->EnqueueEapolStartTimerRunning !=
1969 EAPOL_START_DISABLE) {
1970 DBGPRINT(RT_DEBUG_TRACE,
1971 ("Cancel the EnqueueEapolStartTimerRunning \n"));
1972 RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer,
1974 pEntry->EnqueueEapolStartTimerRunning =
1975 EAPOL_START_DISABLE;
1979 DBGPRINT(RT_DEBUG_TRACE,
1980 ("Receive EAPOLLogoff frame, TYPE = 2 \n"));
1983 Body_len = (*(pData + 2) << 8) | (*(pData + 3));
1984 DBGPRINT(RT_DEBUG_TRACE,
1985 ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n",
1989 DBGPRINT(RT_DEBUG_TRACE,
1990 ("Receive EAPOLASFAlert frame, TYPE = 4 \n"));
2000 ==========================================================================
2002 Report the EAP message type
2005 msg - EAPOL_PAIR_MSG_1
2015 ==========================================================================
2017 PSTRING GetEapolMsgType(CHAR msg)
2019 if (msg == EAPOL_PAIR_MSG_1)
2020 return "Pairwise Message 1";
2021 else if (msg == EAPOL_PAIR_MSG_2)
2022 return "Pairwise Message 2";
2023 else if (msg == EAPOL_PAIR_MSG_3)
2024 return "Pairwise Message 3";
2025 else if (msg == EAPOL_PAIR_MSG_4)
2026 return "Pairwise Message 4";
2027 else if (msg == EAPOL_GROUP_MSG_1)
2028 return "Group Message 1";
2029 else if (msg == EAPOL_GROUP_MSG_2)
2030 return "Group Message 2";
2032 return "Invalid Message";
2036 ========================================================================
2038 Routine Description:
2039 Check Sanity RSN IE of EAPoL message
2045 ========================================================================
2047 BOOLEAN RTMPCheckRSNIE(IN PRTMP_ADAPTER pAd,
2050 IN MAC_TABLE_ENTRY * pEntry, OUT UCHAR * Offset)
2055 BOOLEAN result = FALSE;
2061 while (len > sizeof(RSNIE2)) {
2062 pEid = (PEID_STRUCT) pVIE;
2064 if ((pEid->Eid == IE_WPA)
2065 && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) {
2066 if ((pEntry->AuthMode == Ndis802_11AuthModeWPA
2067 || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK)
2070 (pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len))
2071 && (pEntry->RSNIE_Len == (pEid->Len + 2))) {
2075 *Offset += (pEid->Len + 2);
2078 else if ((pEid->Eid == IE_RSN)
2079 && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) {
2080 if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2
2081 || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)
2082 && (pEid->Eid == pEntry->RSN_IE[0])
2083 && ((pEid->Len + 2) >= pEntry->RSNIE_Len)
2086 (pEid->Octet, &pEntry->RSN_IE[2],
2087 pEntry->RSNIE_Len - 2))) {
2092 *Offset += (pEid->Len + 2);
2097 pVIE += (pEid->Len + 2);
2098 len -= (pEid->Len + 2);
2106 ========================================================================
2108 Routine Description:
2109 Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK.
2110 GTK is encaptulated in KDE format at p.83 802.11i D10
2119 ========================================================================
2121 BOOLEAN RTMPParseEapolKeyData(IN PRTMP_ADAPTER pAd,
2123 IN UCHAR KeyDataLen,
2124 IN UCHAR GroupKeyIndex,
2126 IN BOOLEAN bWPA2, IN MAC_TABLE_ENTRY * pEntry)
2128 PKDE_ENCAP pKDE = NULL;
2129 PUCHAR pMyKeyData = pKeyData;
2130 UCHAR KeyDataLength = KeyDataLen;
2132 UCHAR DefaultIdx = 0;
2135 // Verify The RSN IE contained in pairewise_msg_2 && pairewise_msg_3 and skip it
2136 if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_3) {
2137 // Check RSN IE whether it is WPA2/WPA2PSK
2139 (pAd, pKeyData, KeyDataLen, pEntry, &skip_offset)) {
2140 // send wireless event - for RSN IE different
2141 if (pAd->CommonCfg.bWirelessEvent)
2142 RTMPSendWirelessEvent(pAd,
2143 IW_RSNIE_DIFF_EVENT_FLAG,
2147 DBGPRINT(RT_DEBUG_ERROR,
2148 ("RSN_IE Different in msg %d of 4-way handshake!\n",
2150 hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen);
2151 hex_dump("Desired RSN_IE ", pEntry->RSN_IE,
2156 if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3) {
2157 WpaShowAllsuite(pMyKeyData, skip_offset);
2160 pMyKeyData += skip_offset;
2161 KeyDataLength -= skip_offset;
2162 DBGPRINT(RT_DEBUG_TRACE,
2163 ("RTMPParseEapolKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n",
2170 DBGPRINT(RT_DEBUG_TRACE,
2171 ("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n",
2173 //hex_dump("remain data", pMyKeyData, KeyDataLength);
2175 // Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2
2177 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1)) {
2178 if (KeyDataLength >= 8) // KDE format exclude GTK length
2180 pKDE = (PKDE_ENCAP) pMyKeyData;
2182 DefaultIdx = pKDE->GTKEncap.Kid;
2184 // Sanity check - KED length
2185 if (KeyDataLength < (pKDE->Len + 2)) {
2186 DBGPRINT(RT_DEBUG_ERROR,
2187 ("ERROR: The len from KDE is too short \n"));
2190 // Get GTK length - refer to IEEE 802.11i-2004 p.82
2191 GTKLEN = pKDE->Len - 6;
2192 if (GTKLEN < LEN_AES_KEY) {
2193 DBGPRINT(RT_DEBUG_ERROR,
2194 ("ERROR: GTK Key length is too short (%d) \n",
2200 DBGPRINT(RT_DEBUG_ERROR,
2201 ("ERROR: KDE format length is too short \n"));
2205 DBGPRINT(RT_DEBUG_TRACE,
2206 ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n",
2207 DefaultIdx, GTKLEN));
2212 } else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1) {
2213 DefaultIdx = GroupKeyIndex;
2214 DBGPRINT(RT_DEBUG_TRACE,
2215 ("GTK DefaultKeyID=%d \n", DefaultIdx));
2217 // Sanity check - shared key index must be 1 ~ 3
2218 if (DefaultIdx < 1 || DefaultIdx > 3) {
2219 DBGPRINT(RT_DEBUG_ERROR,
2220 ("ERROR: GTK Key index(%d) is invalid in %s %s \n",
2221 DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"),
2222 GetEapolMsgType(MsgType)));
2227 PCIPHER_KEY pSharedKey;
2229 // set key material, TxMic and RxMic
2230 NdisMoveMemory(pAd->StaCfg.GTK, pMyKeyData, 32);
2231 pAd->StaCfg.DefaultKeyId = DefaultIdx;
2233 pSharedKey = &pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId];
2235 // Prepare pair-wise key information into shared key table
2236 NdisZeroMemory(pSharedKey, sizeof(CIPHER_KEY));
2237 pSharedKey->KeyLen = LEN_TKIP_EK;
2238 NdisMoveMemory(pSharedKey->Key, pAd->StaCfg.GTK, LEN_TKIP_EK);
2239 NdisMoveMemory(pSharedKey->RxMic, &pAd->StaCfg.GTK[16],
2241 NdisMoveMemory(pSharedKey->TxMic, &pAd->StaCfg.GTK[24],
2244 // Update Shared Key CipherAlg
2245 pSharedKey->CipherAlg = CIPHER_NONE;
2246 if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled)
2247 pSharedKey->CipherAlg = CIPHER_TKIP;
2248 else if (pAd->StaCfg.GroupCipher ==
2249 Ndis802_11Encryption3Enabled)
2250 pSharedKey->CipherAlg = CIPHER_AES;
2251 else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled)
2252 pSharedKey->CipherAlg = CIPHER_WEP64;
2253 else if (pAd->StaCfg.GroupCipher ==
2254 Ndis802_11GroupWEP104Enabled)
2255 pSharedKey->CipherAlg = CIPHER_WEP128;
2257 // Update group key information to ASIC Shared Key Table
2258 AsicAddSharedKeyEntry(pAd,
2260 pAd->StaCfg.DefaultKeyId,
2261 pSharedKey->CipherAlg,
2263 pSharedKey->TxMic, pSharedKey->RxMic);
2265 // Update ASIC WCID attribute table and IVEIV table
2266 RTMPAddWcidAttributeEntry(pAd,
2268 pAd->StaCfg.DefaultKeyId,
2269 pSharedKey->CipherAlg, NULL);
2277 ========================================================================
2279 Routine Description:
2280 Construct EAPoL message for WPA handshaking
2281 Its format is below,
2283 +--------------------+
2284 | Protocol Version | 1 octet
2285 +--------------------+
2286 | Protocol Type | 1 octet
2287 +--------------------+
2288 | Body Length | 2 octets
2289 +--------------------+
2290 | Descriptor Type | 1 octet
2291 +--------------------+
2292 | Key Information | 2 octets
2293 +--------------------+
2294 | Key Length | 1 octet
2295 +--------------------+
2296 | Key Repaly Counter | 8 octets
2297 +--------------------+
2298 | Key Nonce | 32 octets
2299 +--------------------+
2300 | Key IV | 16 octets
2301 +--------------------+
2302 | Key RSC | 8 octets
2303 +--------------------+
2304 | Key ID or Reserved | 8 octets
2305 +--------------------+
2306 | Key MIC | 16 octets
2307 +--------------------+
2308 | Key Data Length | 2 octets
2309 +--------------------+
2310 | Key Data | n octets
2311 +--------------------+
2314 pAd Pointer to our adapter
2321 ========================================================================
2323 VOID ConstructEapolMsg(IN PMAC_TABLE_ENTRY pEntry,
2324 IN UCHAR GroupKeyWepStatus,
2326 IN UCHAR DefaultKeyIdx,
2327 IN UCHAR * KeyNonce,
2331 IN UCHAR RSNIE_Len, OUT PEAPOL_PACKET pMsg)
2333 BOOLEAN bWPA2 = FALSE;
2336 // Choose WPA2 or not
2337 if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) ||
2338 (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
2341 // Init Packet and Fill header
2342 pMsg->ProVer = EAPOL_VER;
2343 pMsg->ProType = EAPOLKey;
2345 // Default 95 bytes, the EAPoL-Key descriptor exclude Key-data field
2346 SET_UINT16_TO_ARRARY(pMsg->Body_Len, LEN_EAPOL_KEY_MSG);
2348 // Fill in EAPoL descriptor
2350 pMsg->KeyDesc.Type = WPA2_KEY_DESC;
2352 pMsg->KeyDesc.Type = WPA1_KEY_DESC;
2354 // Key Descriptor Version (bits 0-2) specifies the key descriptor version type
2356 // Fill in Key information, refer to IEEE Std 802.11i-2004 page 78
2357 // When either the pairwise or the group cipher is AES, the DESC_TYPE_AES(2) shall be used.
2359 (((pEntry->WepStatus == Ndis802_11Encryption3Enabled)
2360 || (GroupKeyWepStatus ==
2361 Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES)
2362 : (DESC_TYPE_TKIP));
2365 pMsg->KeyDesc.KeyInfo.KeyDescVer = KeyDescVer;
2367 // Specify Key Type as Group(0) or Pairwise(1)
2368 if (MsgType >= EAPOL_GROUP_MSG_1)
2369 pMsg->KeyDesc.KeyInfo.KeyType = GROUPKEY;
2371 pMsg->KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
2373 // Specify Key Index, only group_msg1_WPA1
2374 if (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))
2375 pMsg->KeyDesc.KeyInfo.KeyIndex = DefaultKeyIdx;
2377 if (MsgType == EAPOL_PAIR_MSG_3)
2378 pMsg->KeyDesc.KeyInfo.Install = 1;
2380 if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3)
2381 || (MsgType == EAPOL_GROUP_MSG_1))
2382 pMsg->KeyDesc.KeyInfo.KeyAck = 1;
2384 if (MsgType != EAPOL_PAIR_MSG_1)
2385 pMsg->KeyDesc.KeyInfo.KeyMic = 1;
2387 if ((bWPA2 && (MsgType >= EAPOL_PAIR_MSG_3)) ||
2388 (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))) {
2389 pMsg->KeyDesc.KeyInfo.Secure = 1;
2392 if (bWPA2 && ((MsgType == EAPOL_PAIR_MSG_3) ||
2393 (MsgType == EAPOL_GROUP_MSG_1))) {
2394 pMsg->KeyDesc.KeyInfo.EKD_DL = 1;
2396 // key Information element has done.
2397 *(USHORT *) (&pMsg->KeyDesc.KeyInfo) =
2398 cpu2le16(*(USHORT *) (&pMsg->KeyDesc.KeyInfo));
2400 // Fill in Key Length
2402 if (MsgType >= EAPOL_GROUP_MSG_1) {
2403 // the length of group key cipher
2404 pMsg->KeyDesc.KeyLength[1] =
2405 ((GroupKeyWepStatus ==
2406 Ndis802_11Encryption2Enabled) ? TKIP_GTK_LENGTH :
2409 // the length of pairwise key cipher
2410 pMsg->KeyDesc.KeyLength[1] =
2411 ((pEntry->WepStatus ==
2412 Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY :
2417 // Fill in replay counter
2418 NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter,
2419 LEN_KEY_DESC_REPLAY);
2421 // Fill Key Nonce field
2422 // ANonce : pairwise_msg1 & pairwise_msg3
2423 // SNonce : pairwise_msg2
2424 // GNonce : group_msg1_wpa1
2425 if ((MsgType <= EAPOL_PAIR_MSG_3)
2426 || ((!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1))))
2427 NdisMoveMemory(pMsg->KeyDesc.KeyNonce, KeyNonce,
2428 LEN_KEY_DESC_NONCE);
2430 // Fill key IV - WPA2 as 0, WPA1 as random
2431 if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) {
2432 // Suggest IV be random number plus some number,
2433 NdisMoveMemory(pMsg->KeyDesc.KeyIv, &KeyNonce[16],
2435 pMsg->KeyDesc.KeyIv[15] += 2;
2437 // Fill Key RSC field
2438 // It contains the RSC for the GTK being installed.
2439 if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2)
2440 || (MsgType == EAPOL_GROUP_MSG_1)) {
2441 NdisMoveMemory(pMsg->KeyDesc.KeyRsc, TxRSC, 6);
2443 // Clear Key MIC field for MIC calculation later
2444 NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
2446 ConstructEapolKeyData(pEntry,
2450 DefaultKeyIdx, GTK, RSNIE, RSNIE_Len, pMsg);
2452 // Calculate MIC and fill in KeyMic Field except Pairwise Msg 1.
2453 if (MsgType != EAPOL_PAIR_MSG_1) {
2454 CalculateMIC(KeyDescVer, pEntry->PTK, pMsg);
2457 DBGPRINT(RT_DEBUG_TRACE,
2458 ("===> ConstructEapolMsg for %s %s\n",
2459 ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType)));
2460 DBGPRINT(RT_DEBUG_TRACE,
2461 (" Body length = %d \n",
2462 CONV_ARRARY_TO_UINT16(pMsg->Body_Len)));
2463 DBGPRINT(RT_DEBUG_TRACE,
2464 (" Key length = %d \n",
2465 CONV_ARRARY_TO_UINT16(pMsg->KeyDesc.KeyLength)));
2470 ========================================================================
2472 Routine Description:
2473 Construct the Key Data field of EAPoL message
2476 pAd Pointer to our adapter
2484 ========================================================================
2486 VOID ConstructEapolKeyData(IN PMAC_TABLE_ENTRY pEntry,
2487 IN UCHAR GroupKeyWepStatus,
2488 IN UCHAR keyDescVer,
2490 IN UCHAR DefaultKeyIdx,
2493 IN UCHAR RSNIE_LEN, OUT PEAPOL_PACKET pMsg)
2495 UCHAR *mpool, *Key_Data, *Rc4GTK;
2496 UCHAR ekey[(LEN_KEY_DESC_IV + LEN_EAP_EK)];
2498 BOOLEAN bWPA2Capable = FALSE;
2499 PRTMP_ADAPTER pAd = pEntry->pAd;
2500 BOOLEAN GTK_Included = FALSE;
2502 // Choose WPA2 or not
2503 if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) ||
2504 (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
2505 bWPA2Capable = TRUE;
2507 if (MsgType == EAPOL_PAIR_MSG_1 ||
2508 MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2)
2511 // allocate memory pool
2512 os_alloc_mem(NULL, (PUCHAR *) & mpool, 1500);
2517 /* Rc4GTK Len = 512 */
2518 Rc4GTK = (UCHAR *) ROUND_UP(mpool, 4);
2519 /* Key_Data Len = 512 */
2520 Key_Data = (UCHAR *) ROUND_UP(Rc4GTK + 512, 4);
2522 NdisZeroMemory(Key_Data, 512);
2523 SET_UINT16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, 0);
2526 // Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3
2528 && ((MsgType == EAPOL_PAIR_MSG_2)
2529 || (MsgType == EAPOL_PAIR_MSG_3))) {
2530 PUINT8 pmkid_ptr = NULL;
2531 UINT8 pmkid_len = 0;
2533 RTMPInsertRSNIE(&Key_Data[data_offset],
2535 RSNIE, RSNIE_LEN, pmkid_ptr, pmkid_len);
2538 // Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2
2540 && ((MsgType == EAPOL_PAIR_MSG_3)
2541 || (MsgType == EAPOL_GROUP_MSG_1))) {
2542 // Key Data Encapsulation (KDE) format - 802.11i-2004 Figure-43w and Table-20h
2543 Key_Data[data_offset + 0] = 0xDD;
2545 if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) {
2546 Key_Data[data_offset + 1] = 0x16; // 4+2+16(OUI+DataType+DataField)
2548 Key_Data[data_offset + 1] = 0x26; // 4+2+32(OUI+DataType+DataField)
2551 Key_Data[data_offset + 2] = 0x00;
2552 Key_Data[data_offset + 3] = 0x0F;
2553 Key_Data[data_offset + 4] = 0xAC;
2554 Key_Data[data_offset + 5] = 0x01;
2556 // GTK KDE format - 802.11i-2004 Figure-43x
2557 Key_Data[data_offset + 6] = (DefaultKeyIdx & 0x03);
2558 Key_Data[data_offset + 7] = 0x00; // Reserved Byte
2564 // Only for pairwise_msg3_WPA2 and group_msg1
2565 if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable)
2566 || (MsgType == EAPOL_GROUP_MSG_1)) {
2568 if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) {
2569 NdisMoveMemory(&Key_Data[data_offset], GTK,
2571 data_offset += LEN_AES_KEY;
2573 NdisMoveMemory(&Key_Data[data_offset], GTK,
2575 data_offset += TKIP_GTK_LENGTH;
2578 GTK_Included = TRUE;
2581 // This whole key-data field shall be encrypted if a GTK is included.
2582 // Encrypt the data material in key data field with KEK
2584 //hex_dump("GTK_Included", Key_Data, data_offset);
2586 if ((keyDescVer == DESC_TYPE_AES)) {
2587 UCHAR remainder = 0;
2590 // Key Descriptor Version 2 or 3: AES key wrap, defined in IETF RFC 3394,
2591 // shall be used to encrypt the Key Data field using the KEK field from
2594 // If the Key Data field uses the NIST AES key wrap, then the Key Data field
2595 // shall be padded before encrypting if the key data length is less than 16
2596 // octets or if it is not a multiple of 8. The padding consists of appending
2597 // a single octet 0xdd followed by zero or more 0x00 octets.
2598 if ((remainder = data_offset & 0x07) != 0) {
2601 pad_len = (8 - remainder);
2602 Key_Data[data_offset] = 0xDD;
2603 for (i = 1; i < pad_len; i++)
2604 Key_Data[data_offset + i] = 0;
2606 data_offset += pad_len;
2609 AES_GTK_KEY_WRAP(&pEntry->PTK[16], Key_Data,
2610 data_offset, Rc4GTK);
2611 // AES wrap function will grow 8 bytes in length
2614 /* Key Descriptor Version 1: ARC4 is used to encrypt the Key Data field
2615 using the KEK field from the derived PTK. */
2617 // PREPARE Encrypted "Key DATA" field. (Encrypt GTK with RC4, usinf PTK[16]->[31] as Key, IV-field as IV)
2618 // put TxTsc in Key RSC field
2619 pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32.
2621 // ekey is the contanetion of IV-field, and PTK[16]->PTK[31]
2622 NdisMoveMemory(ekey, pMsg->KeyDesc.KeyIv,
2624 NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &pEntry->PTK[16],
2626 ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, ekey, sizeof(ekey)); //INIT SBOX, KEYLEN+3(IV)
2627 pAd->PrivateInfo.FCSCRC32 =
2628 RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, Key_Data,
2630 WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK,
2631 Key_Data, data_offset);
2634 NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset);
2636 NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset);
2639 // Update key data length field and total body length
2640 SET_UINT16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, data_offset);
2641 INC_UINT16_TO_ARRARY(pMsg->Body_Len, data_offset);
2643 os_free_mem(NULL, mpool);
2648 ========================================================================
2650 Routine Description:
2651 Calcaulate MIC. It is used during 4-ways handsharking.
2654 pAd - pointer to our pAdapter context
2655 PeerWepStatus - indicate the encryption type
2661 ========================================================================
2663 static VOID CalculateMIC(IN UCHAR KeyDescVer,
2664 IN UCHAR * PTK, OUT PEAPOL_PACKET pMsg)
2668 UCHAR mic[LEN_KEY_DESC_MIC];
2671 // allocate memory for MIC calculation
2672 os_alloc_mem(NULL, (PUCHAR *) & OutBuffer, 512);
2674 if (OutBuffer == NULL) {
2675 DBGPRINT(RT_DEBUG_ERROR, ("!!!CalculateMIC: no memory!!!\n"));
2678 // make a frame for calculating MIC.
2679 MakeOutgoingFrame(OutBuffer, &FrameLen,
2680 CONV_ARRARY_TO_UINT16(pMsg->Body_Len) + 4, pMsg,
2683 NdisZeroMemory(mic, sizeof(mic));
2686 if (KeyDescVer == DESC_TYPE_AES) {
2687 HMAC_SHA1(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, digest,
2689 NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC);
2691 HMAC_MD5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, mic,
2695 // store the calculated MIC
2696 NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC);
2698 os_free_mem(NULL, OutBuffer);
2702 ========================================================================
2704 Routine Description:
2705 Some received frames can't decrypt by Asic, so decrypt them by software.
2708 pAd - pointer to our pAdapter context
2709 PeerWepStatus - indicate the encryption type
2712 NDIS_STATUS_SUCCESS - decryption successful
2713 NDIS_STATUS_FAILURE - decryption failure
2715 ========================================================================
2717 NDIS_STATUS RTMPSoftDecryptBroadCastData(IN PRTMP_ADAPTER pAd,
2719 IN NDIS_802_11_ENCRYPTION_STATUS
2720 GroupCipher, IN PCIPHER_KEY pShard_key)
2722 PRXWI_STRUC pRxWI = pRxBlk->pRxWI;
2724 // handle WEP decryption
2725 if (GroupCipher == Ndis802_11Encryption1Enabled) {
2726 if (RTMPSoftDecryptWEP
2727 (pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount,
2730 //Minus IV[4] & ICV[4]
2731 pRxWI->MPDUtotalByteCount -= 8;
2733 DBGPRINT(RT_DEBUG_ERROR,
2734 ("ERROR : Software decrypt WEP data fails.\n"));
2735 // give up this frame
2736 return NDIS_STATUS_FAILURE;
2739 // handle TKIP decryption
2740 else if (GroupCipher == Ndis802_11Encryption2Enabled) {
2741 if (RTMPSoftDecryptTKIP
2742 (pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0,
2745 //Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV
2746 pRxWI->MPDUtotalByteCount -= 20;
2748 DBGPRINT(RT_DEBUG_ERROR,
2749 ("ERROR : RTMPSoftDecryptTKIP Failed\n"));
2750 // give up this frame
2751 return NDIS_STATUS_FAILURE;
2754 // handle AES decryption
2755 else if (GroupCipher == Ndis802_11Encryption3Enabled) {
2756 if (RTMPSoftDecryptAES
2757 (pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount,
2760 //8 bytes MIC, 8 bytes IV/EIV (CCMP Header)
2761 pRxWI->MPDUtotalByteCount -= 16;
2763 DBGPRINT(RT_DEBUG_ERROR,
2764 ("ERROR : RTMPSoftDecryptAES Failed\n"));
2765 // give up this frame
2766 return NDIS_STATUS_FAILURE;
2769 // give up this frame
2770 return NDIS_STATUS_FAILURE;
2773 return NDIS_STATUS_SUCCESS;
2777 PUINT8 GetSuiteFromRSNIE(IN PUINT8 rsnie,
2778 IN UINT rsnie_len, IN UINT8 type, OUT UINT8 * count)
2786 BOOLEAN isWPA2 = FALSE;
2788 pEid = (PEID_STRUCT) rsnie;
2789 len = rsnie_len - 2; // exclude IE and length
2790 pBuf = (PUINT8) & pEid->Octet[0];
2792 // set default value
2796 if ((len <= 0) || (pEid->Len != len)) {
2797 DBGPRINT_ERR(("%s : The length is invalid\n", __func__));
2800 // Check WPA or WPA2
2801 if (pEid->Eid == IE_WPA) {
2802 PRSNIE pRsnie = (PRSNIE) pBuf;
2805 if (len < sizeof(RSNIE)) {
2806 DBGPRINT_ERR(("%s : The length is too short for WPA\n",
2810 // Get the count of pairwise cipher
2811 ucount = cpu2le16(pRsnie->ucount);
2813 DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount));
2816 // Get the group cipher
2817 if (type == GROUP_SUITE) {
2819 return pRsnie->mcast;
2821 // Get the pairwise cipher suite
2822 else if (type == PAIRWISE_SUITE) {
2823 DBGPRINT(RT_DEBUG_TRACE,
2824 ("%s : The count of pairwise cipher is %d\n",
2827 return pRsnie->ucast[0].oui;
2830 offset = sizeof(RSNIE) + (4 * (ucount - 1));
2832 } else if (pEid->Eid == IE_RSN) {
2833 PRSNIE2 pRsnie = (PRSNIE2) pBuf;
2838 if (len < sizeof(RSNIE2)) {
2839 DBGPRINT_ERR(("%s : The length is too short for WPA2\n",
2843 // Get the count of pairwise cipher
2844 ucount = cpu2le16(pRsnie->ucount);
2846 DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount));
2849 // Get the group cipher
2850 if (type == GROUP_SUITE) {
2852 return pRsnie->mcast;
2854 // Get the pairwise cipher suite
2855 else if (type == PAIRWISE_SUITE) {
2856 DBGPRINT(RT_DEBUG_TRACE,
2857 ("%s : The count of pairwise cipher is %d\n",
2860 return pRsnie->ucast[0].oui;
2863 offset = sizeof(RSNIE2) + (4 * (ucount - 1));
2866 DBGPRINT_ERR(("%s : Unknown IE (%d)\n", __func__, pEid->Eid));
2870 // skip group cipher and pairwise cipher suite
2874 if (len < sizeof(RSNIE_AUTH)) {
2875 DBGPRINT_ERR(("%s : The length of RSNIE is too short\n",
2879 // pointer to AKM count
2880 pAkm = (PRSNIE_AUTH) pBuf;
2882 // Get the count of pairwise cipher
2883 acount = cpu2le16(pAkm->acount);
2885 DBGPRINT_ERR(("%s : The count(%d) of AKM is invlaid\n",
2889 // Get the AKM suite
2890 if (type == AKM_SUITE) {
2891 DBGPRINT(RT_DEBUG_TRACE, ("%s : The count of AKM is %d\n",
2894 return pAkm->auth[0].oui;
2896 offset = sizeof(RSNIE_AUTH) + (4 * (acount - 1));
2901 // The remaining length must larger than (RSN-Capability(2) + PMKID-Count(2) + PMKID(16~))
2902 if (len >= (sizeof(RSN_CAPABILITIES) + 2 + LEN_PMKID)) {
2903 // Skip RSN capability and PMKID-Count
2904 pBuf += (sizeof(RSN_CAPABILITIES) + 2);
2905 len -= (sizeof(RSN_CAPABILITIES) + 2);
2908 if (type == PMKID_LIST) {
2913 DBGPRINT_ERR(("%s : it can't get any more information beyond AKM \n", __func__));
2918 //DBGPRINT_ERR(("%s : The type(%d) doesn't support \n", __func__, type));
2923 VOID WpaShowAllsuite(IN PUINT8 rsnie, IN UINT rsnie_len)
2925 PUINT8 pSuite = NULL;
2928 hex_dump("RSNIE", rsnie, rsnie_len);
2932 GetSuiteFromRSNIE(rsnie, rsnie_len, GROUP_SUITE,
2934 hex_dump("group cipher", pSuite, 4 * count);
2938 GetSuiteFromRSNIE(rsnie, rsnie_len, PAIRWISE_SUITE,
2940 hex_dump("pairwise cipher", pSuite, 4 * count);
2944 GetSuiteFromRSNIE(rsnie, rsnie_len, AKM_SUITE, &count)) != NULL) {
2945 hex_dump("AKM suite", pSuite, 4 * count);
2949 GetSuiteFromRSNIE(rsnie, rsnie_len, PMKID_LIST, &count)) != NULL) {
2950 hex_dump("PMKID", pSuite, LEN_PMKID);
2955 VOID RTMPInsertRSNIE(IN PUCHAR pFrameBuf,
2956 OUT PULONG pFrameLen,
2957 IN PUINT8 rsnie_ptr,
2959 IN PUINT8 pmkid_ptr, IN UINT8 pmkid_len)
2963 UINT8 extra_len = 0;
2964 UINT16 pmk_count = 0;
2966 UINT8 total_len = 0;
2967 UCHAR WPA2_OUI[3] = { 0x00, 0x0F, 0xAC };
2969 pTmpBuf = pFrameBuf;
2971 /* PMKID-List Must larger than 0 and the multiple of 16. */
2972 if (pmkid_len > 0 && ((pmkid_len & 0x0f) == 0)) {
2973 extra_len = sizeof(UINT16) + pmkid_len;
2975 pmk_count = (pmkid_len >> 4);
2976 pmk_count = cpu2le16(pmk_count);
2978 DBGPRINT(RT_DEBUG_WARN,
2979 ("%s : The length is PMKID-List is invalid (%d), so don't insert it.\n",
2980 __func__, pmkid_len));
2983 if (rsnie_len != 0) {
2985 total_len = rsnie_len;
2987 if (NdisEqualMemory(rsnie_ptr + 2, WPA2_OUI, sizeof(WPA2_OUI))) {
2989 total_len += extra_len;
2992 /* construct RSNIE body */
2993 MakeOutgoingFrame(pTmpBuf, &TempLen,
2996 rsnie_len, rsnie_ptr, END_OF_ARGS);
2999 *pFrameLen = *pFrameLen + TempLen;
3001 if (ie_num == IE_RSN) {
3002 /* Insert PMKID-List field */
3003 if (extra_len > 0) {
3004 MakeOutgoingFrame(pTmpBuf, &TempLen,
3006 pmkid_len, pmkid_ptr,
3010 *pFrameLen = *pFrameLen + TempLen;