fix typos concerning "initiali[zs]e"
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / rt2860 / common / cmm_wpa.c
blobe1ead76b907d05a085a014cf4396fe1a3f913ee7
1 /*
2 *************************************************************************
3 * Ralink Tech Inc.
4 * 5F., No.36, Taiyuan St., Jhubei City,
5 * Hsinchu County 302,
6 * Taiwan, R.O.C.
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. *
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 *************************************************************************
27 Module Name:
28 wpa.c
30 Abstract:
32 Revision History:
33 Who When What
34 -------- ---------- ----------------------------------------------
35 Jan Lee 03-07-22 Initial
36 Paul Lin 03-11-28 Modify for supplicant
38 #include "../rt_config.h"
39 /* WPA OUI */
40 u8 OUI_WPA_NONE_AKM[4] = { 0x00, 0x50, 0xF2, 0x00 };
41 u8 OUI_WPA_VERSION[4] = { 0x00, 0x50, 0xF2, 0x01 };
42 u8 OUI_WPA_WEP40[4] = { 0x00, 0x50, 0xF2, 0x01 };
43 u8 OUI_WPA_TKIP[4] = { 0x00, 0x50, 0xF2, 0x02 };
44 u8 OUI_WPA_CCMP[4] = { 0x00, 0x50, 0xF2, 0x04 };
45 u8 OUI_WPA_WEP104[4] = { 0x00, 0x50, 0xF2, 0x05 };
46 u8 OUI_WPA_8021X_AKM[4] = { 0x00, 0x50, 0xF2, 0x01 };
47 u8 OUI_WPA_PSK_AKM[4] = { 0x00, 0x50, 0xF2, 0x02 };
49 /* WPA2 OUI */
50 u8 OUI_WPA2_WEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 };
51 u8 OUI_WPA2_TKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 };
52 u8 OUI_WPA2_CCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 };
53 u8 OUI_WPA2_8021X_AKM[4] = { 0x00, 0x0F, 0xAC, 0x01 };
54 u8 OUI_WPA2_PSK_AKM[4] = { 0x00, 0x0F, 0xAC, 0x02 };
55 u8 OUI_WPA2_WEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 };
57 static void ConstructEapolKeyData(struct rt_mac_table_entry *pEntry,
58 u8 GroupKeyWepStatus,
59 u8 keyDescVer,
60 u8 MsgType,
61 u8 DefaultKeyIdx,
62 u8 * GTK,
63 u8 * RSNIE,
64 u8 RSNIE_LEN, struct rt_eapol_packet * pMsg);
66 static void CalculateMIC(u8 KeyDescVer,
67 u8 * PTK, struct rt_eapol_packet * pMsg);
69 static void WpaEAPPacketAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem);
71 static void WpaEAPOLASFAlertAction(struct rt_rtmp_adapter *pAd,
72 struct rt_mlme_queue_elem *Elem);
74 static void WpaEAPOLLogoffAction(struct rt_rtmp_adapter *pAd,
75 struct rt_mlme_queue_elem *Elem);
77 static void WpaEAPOLStartAction(struct rt_rtmp_adapter *pAd,
78 struct rt_mlme_queue_elem *Elem);
80 static void WpaEAPOLKeyAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem);
83 ==========================================================================
84 Description:
85 association state machine init, including state transition and timer init
86 Parameters:
87 S - pointer to the association state machine
88 ==========================================================================
90 void WpaStateMachineInit(struct rt_rtmp_adapter *pAd,
91 struct rt_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,
95 WPA_MACHINE_BASE);
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 ==========================================================================
111 Description:
112 this is state machine function.
113 When receiving EAP packets which is for 802.1x authentication use.
114 Not use in PSK case
115 Return:
116 ==========================================================================
118 void WpaEAPPacketAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
122 void WpaEAPOLASFAlertAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
126 void WpaEAPOLLogoffAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
131 ==========================================================================
132 Description:
133 Start 4-way HS when rcv EAPOL_START which may create by our driver in assoc.c
134 Return:
135 ==========================================================================
137 void WpaEAPOLStartAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
139 struct rt_mac_table_entry *pEntry;
140 struct rt_header_802_11 * pHeader;
142 DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLStartAction ===> \n"));
144 pHeader = (struct rt_header_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);
149 else {
150 pEntry = MacTableLookup(pAd, pHeader->Addr2);
153 if (pEntry) {
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 ==========================================================================
179 Description:
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
187 Return:
188 ==========================================================================
190 void WpaEAPOLKeyAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
192 struct rt_mac_table_entry *pEntry;
193 struct rt_header_802_11 * pHeader;
194 struct rt_eapol_packet * pEapol_packet;
195 struct rt_key_info peerKeyInfo;
197 DBGPRINT(RT_DEBUG_TRACE, ("WpaEAPOLKeyAction ===>\n"));
199 pHeader = (struct rt_header_802_11 *) Elem->Msg;
200 pEapol_packet =
201 (struct rt_eapol_packet *) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
203 NdisZeroMemory((u8 *)& peerKeyInfo, sizeof(peerKeyInfo));
204 NdisMoveMemory((u8 *)& peerKeyInfo,
205 (u8 *)& pEapol_packet->KeyDesc.KeyInfo,
206 sizeof(struct rt_key_info));
208 hex_dump("Received Eapol frame", (unsigned char *)pEapol_packet,
209 (Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H));
211 *((u16 *) & peerKeyInfo) = cpu2le16(*((u16 *) & peerKeyInfo));
213 do {
214 pEntry = MacTableLookup(pAd, pHeader->Addr2);
216 if (!pEntry
217 || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
218 break;
220 if (pEntry->AuthMode < Ndis802_11AuthModeWPA)
221 break;
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"));
233 break;
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"));
241 break;
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"));
249 break;
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 */
255 /* or not. */
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,
272 Elem);
273 else
274 PeerPairMsg3Action(pAd, pEntry,
275 Elem);
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,
286 Elem);
287 else
288 PeerGroupMsg1Action(pAd, pEntry,
289 Elem);
291 } else {
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 ==
299 PAIRWISEKEY) {
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_u16
304 (pEapol_packet->KeyDesc.
305 KeyDataLen) == 0) {
306 PeerPairMsg4Action(pAd,
307 pEntry,
308 Elem);
309 } else {
310 PeerPairMsg2Action(pAd,
311 pEntry,
312 Elem);
314 } else if (peerKeyInfo.Secure == 1
315 && peerKeyInfo.KeyType ==
316 PAIRWISEKEY) {
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,
320 Elem);
321 } else if (peerKeyInfo.Secure == 1
322 && peerKeyInfo.KeyType ==
323 GROUPKEY) {
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,
327 &Elem->
329 [LENGTH_802_11],
330 (Elem->
331 MsgLen -
332 LENGTH_802_11));
337 } while (FALSE);
341 ========================================================================
343 Routine Description:
344 Copy frame from waiting queue into relative ring buffer and set
345 appropriate ASIC register to kick hardware encryption before really
346 sent out to air.
348 Arguments:
349 pAd Pointer to our adapter
350 void * Pointer to outgoing Ndis frame
351 NumberOfFrag Number of fragment required
353 Return Value:
354 None
356 Note:
358 ========================================================================
360 void RTMPToWirelessSta(struct rt_rtmp_adapter *pAd,
361 struct rt_mac_table_entry *pEntry,
362 u8 *pHeader802_3,
363 u32 HdrLen,
364 u8 *pData, u32 DataLen, IN BOOLEAN bClearFrame)
366 void *pPacket;
367 int Status;
369 if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
370 return;
372 do {
373 /* build a NDIS packet */
374 Status =
375 RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen,
376 pData, DataLen);
377 if (Status != NDIS_STATUS_SUCCESS)
378 break;
380 if (bClearFrame)
381 RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1);
382 else
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,
390 pEntry->
391 apidx);
393 RTMP_SET_PACKET_WCID(pPacket, (u8)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) {
401 u8 Index;
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 */
408 if ((!RTMP_TEST_FLAG
409 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
411 (!RTMP_TEST_FLAG
412 (pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))) {
413 for (Index = 0; Index < 5; Index++)
414 if (pAd->TxSwQueue[Index].
415 Number > 0)
416 RTMPDeQueuePacket(pAd,
417 FALSE,
418 Index,
419 MAX_TX_PROCESS);
424 } while (FALSE);
428 ==========================================================================
429 Description:
430 This is a function to initialize 4-way handshake
432 Return:
434 ==========================================================================
436 void WPAStart4WayHS(struct rt_rtmp_adapter *pAd,
437 struct rt_mac_table_entry *pEntry, unsigned long TimeInterval)
439 u8 Header802_3[14];
440 struct rt_eapol_packet EAPOLPKT;
441 u8 *pBssid = NULL;
442 u8 group_cipher = Ndis802_11WEPDisabled;
444 DBGPRINT(RT_DEBUG_TRACE, ("===> WPAStart4WayHS\n"));
446 if (RTMP_TEST_FLAG
447 (pAd,
448 fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS))
450 DBGPRINT(RT_DEBUG_ERROR,
451 ("[ERROR]WPAStart4WayHS : The interface is closed...\n"));
452 return;
455 if (pBssid == NULL) {
456 DBGPRINT(RT_DEBUG_ERROR,
457 ("[ERROR]WPAStart4WayHS : No corresponding Authenticator.\n"));
458 return;
460 /* Check the status */
461 if ((pEntry->WpaState > AS_PTKSTART) || (pEntry->WpaState < AS_INITPMK)) {
462 DBGPRINT(RT_DEBUG_ERROR,
463 ("[ERROR]WPAStart4WayHS : Not expect calling\n"));
464 return;
467 /* Increment replay counter by 1 */
468 ADD_ONE_To_64BIT_VAR(pEntry->R_Counter);
470 /* Randomly generate ANonce */
471 GenRandom(pAd, (u8 *) 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(struct rt_eapol_packet));
476 ConstructEapolMsg(pEntry, group_cipher, EAPOL_PAIR_MSG_1, 0, /* Default key index */
477 pEntry->ANonce, NULL, /* TxRSC */
478 NULL, /* GTK */
479 NULL, /* RSNIE */
480 0, /* RSNIE length */
481 &EAPOLPKT);
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, (u8 *)& EAPOLPKT,
487 CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4,
488 (pEntry->PortSecured ==
489 WPA_802_1X_PORT_SECURED) ? FALSE : TRUE);
491 /* Trigger Retry Timer */
492 RTMPModTimer(&pEntry->RetryTimer, TimeInterval);
494 /* Update State */
495 pEntry->WpaState = AS_PTKSTART;
497 DBGPRINT(RT_DEBUG_TRACE,
498 ("<=== WPAStart4WayHS: send Msg1 of 4-way \n"));
503 ========================================================================
505 Routine Description:
506 Process Pairwise key Msg-1 of 4-way handshaking and send Msg-2
508 Arguments:
509 pAd Pointer to our adapter
510 Elem Message body
512 Return Value:
513 None
515 Note:
517 ========================================================================
519 void PeerPairMsg1Action(struct rt_rtmp_adapter *pAd,
520 struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
522 u8 PTK[80];
523 u8 Header802_3[14];
524 struct rt_eapol_packet * pMsg1;
525 u32 MsgLen;
526 struct rt_eapol_packet EAPOLPKT;
527 u8 *pCurrentAddr = NULL;
528 u8 *pmk_ptr = NULL;
529 u8 group_cipher = Ndis802_11WEPDisabled;
530 u8 *rsnie_ptr = NULL;
531 u8 rsnie_len = 0;
533 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg1Action \n"));
535 if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
536 return;
538 if (Elem->MsgLen <
539 (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
540 sizeof(struct rt_key_descripter) - MAX_LEN_OF_RSNIE - 2))
541 return;
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 = (struct rt_eapol_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)
557 == FALSE)
558 return;
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);
564 /* Store ANonce */
565 NdisMoveMemory(pEntry->ANonce, pMsg1->KeyDesc.KeyNonce,
566 LEN_KEY_DESC_NONCE);
568 /* Generate random SNonce */
569 GenRandom(pAd, (u8 *) pCurrentAddr, pEntry->SNonce);
572 /* Calculate PTK(ANonce, SNonce) */
573 WpaDerivePTK(pAd,
574 pmk_ptr,
575 pEntry->ANonce,
576 pEntry->Addr,
577 pEntry->SNonce, pCurrentAddr, PTK, LEN_PTK);
579 /* Save key to PTK entry */
580 NdisMoveMemory(pEntry->PTK, PTK, LEN_PTK);
583 /* Update WpaState */
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(struct rt_eapol_packet));
589 ConstructEapolMsg(pEntry, group_cipher, EAPOL_PAIR_MSG_2, 0, /* DefaultKeyIdx */
590 pEntry->SNonce, NULL, /* TxRsc */
591 NULL, /* GTK */
592 (u8 *) 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), (u8 *)& EAPOLPKT,
599 CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4, TRUE);
601 DBGPRINT(RT_DEBUG_TRACE,
602 ("<=== PeerPairMsg1Action: send Msg2 of 4-way \n"));
606 ==========================================================================
607 Description:
608 When receiving the second packet of 4-way pairwisekey handshake.
609 Return:
610 ==========================================================================
612 void PeerPairMsg2Action(struct rt_rtmp_adapter *pAd,
613 struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
615 u8 PTK[80];
616 BOOLEAN Cancelled;
617 struct rt_header_802_11 * pHeader;
618 struct rt_eapol_packet EAPOLPKT;
619 struct rt_eapol_packet * pMsg2;
620 u32 MsgLen;
621 u8 Header802_3[LENGTH_802_3];
622 u8 TxTsc[6];
623 u8 *pBssid = NULL;
624 u8 *pmk_ptr = NULL;
625 u8 *gtk_ptr = NULL;
626 u8 default_key = 0;
627 u8 group_cipher = Ndis802_11WEPDisabled;
628 u8 *rsnie_ptr = NULL;
629 u8 rsnie_len = 0;
631 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg2Action \n"));
633 if ((!pEntry) || (!pEntry->ValidAsCLI))
634 return;
636 if (Elem->MsgLen <
637 (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
638 sizeof(struct rt_key_descripter) - MAX_LEN_OF_RSNIE - 2))
639 return;
641 /* check Entry in valid State */
642 if (pEntry->WpaState < AS_PTKSTART)
643 return;
645 /* pointer to 802.11 header */
646 pHeader = (struct rt_header_802_11 *) Elem->Msg;
648 /* skip 802.11_header(24-byte) and LLC_header(8) */
649 pMsg2 = (struct rt_eapol_packet *) & Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
650 MsgLen = Elem->MsgLen - LENGTH_802_11 - LENGTH_802_1_H;
652 /* Store SNonce */
653 NdisMoveMemory(pEntry->SNonce, pMsg2->KeyDesc.KeyNonce,
654 LEN_KEY_DESC_NONCE);
657 /* Derive PTK */
658 WpaDerivePTK(pAd, (u8 *) pmk_ptr, pEntry->ANonce, /* ANONCE */
659 (u8 *) 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)
667 == FALSE)
668 return;
670 do {
671 /* delete retry timer */
672 RTMPCancelTimer(&pEntry->RetryTimer, &Cancelled);
674 /* Change state */
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(struct rt_eapol_packet));
682 ConstructEapolMsg(pEntry,
683 group_cipher,
684 EAPOL_PAIR_MSG_3,
685 default_key,
686 pEntry->ANonce,
687 TxTsc,
688 (u8 *) gtk_ptr,
689 (u8 *) 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,
694 (u8 *)& EAPOLPKT,
695 CONV_ARRARY_TO_u16(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);
702 /* Update State */
703 pEntry->WpaState = AS_PTKINIT_NEGOTIATING;
704 } while (FALSE);
706 DBGPRINT(RT_DEBUG_TRACE,
707 ("<=== PeerPairMsg2Action: send Msg3 of 4-way \n"));
711 ========================================================================
713 Routine Description:
714 Process Pairwise key Msg 3 of 4-way handshaking and send Msg 4
716 Arguments:
717 pAd Pointer to our adapter
718 Elem Message body
720 Return Value:
721 None
723 Note:
725 ========================================================================
727 void PeerPairMsg3Action(struct rt_rtmp_adapter *pAd,
728 struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
730 struct rt_header_802_11 * pHeader;
731 u8 Header802_3[14];
732 struct rt_eapol_packet EAPOLPKT;
733 struct rt_eapol_packet * pMsg3;
734 u32 MsgLen;
735 u8 *pCurrentAddr = NULL;
736 u8 group_cipher = Ndis802_11WEPDisabled;
738 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg3Action \n"));
740 if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
741 return;
743 if (Elem->MsgLen <
744 (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
745 sizeof(struct rt_key_descripter) - MAX_LEN_OF_RSNIE - 2))
746 return;
749 pCurrentAddr = pAd->CurrentAddress;
750 group_cipher = pAd->StaCfg.GroupCipher;
754 /* Record 802.11 header & the received EAPOL packet Msg3 */
755 pHeader = (struct rt_header_802_11 *) Elem->Msg;
756 pMsg3 = (struct rt_eapol_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)
761 == FALSE)
762 return;
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 */
769 if (!NdisEqualMemory
770 (pEntry->ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) {
771 return;
773 /* Construct EAPoL message - Pairwise Msg 4 */
774 NdisZeroMemory(&EAPOLPKT, sizeof(struct rt_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 */
780 0, &EAPOLPKT);
782 /* Update WpaState */
783 pEntry->WpaState = AS_PTKINITDONE;
785 /* Update pairwise key */
787 struct rt_cipher_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(struct rt_cipher_key));
795 pSharedKey->KeyLen = LEN_TKIP_EK;
796 NdisMoveMemory(pSharedKey->Key, &pAd->StaCfg.PTK[32],
797 LEN_TKIP_EK);
798 NdisMoveMemory(pSharedKey->RxMic, &pAd->StaCfg.PTK[48],
799 LEN_TKIP_RXMICK);
800 NdisMoveMemory(pSharedKey->TxMic,
801 &pAd->StaCfg.PTK[48 + LEN_TKIP_RXMICK],
802 LEN_TKIP_TXMICK);
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;
809 else
810 pSharedKey->CipherAlg = CIPHER_NONE;
812 /* Update these related information to struct rt_mac_table_entry */
813 pEntry = &pAd->MacTab.Content[BSSID_WCID];
814 NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32],
815 LEN_TKIP_EK);
816 NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48],
817 LEN_TKIP_RXMICK);
818 NdisMoveMemory(pEntry->PairwiseKey.TxMic,
819 &pAd->StaCfg.PTK[48 + LEN_TKIP_RXMICK],
820 LEN_TKIP_TXMICK);
821 pEntry->PairwiseKey.CipherAlg = pSharedKey->CipherAlg;
823 /* Update pairwise key information to ASIC Shared Key Table */
824 AsicAddSharedKeyEntry(pAd,
825 BSS0,
827 pSharedKey->CipherAlg,
828 pSharedKey->Key,
829 pSharedKey->TxMic, pSharedKey->RxMic);
831 /* Update ASIC WCID attribute table and IVEIV table */
832 RTMPAddWcidAttributeEntry(pAd,
833 BSS0,
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)));
852 } else {
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),
859 (u8 *)& EAPOLPKT,
860 CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4, TRUE);
862 DBGPRINT(RT_DEBUG_TRACE,
863 ("<=== PeerPairMsg3Action: send Msg4 of 4-way \n"));
867 ==========================================================================
868 Description:
869 When receiving the last packet of 4-way pairwisekey handshake.
870 Initialize 2-way groupkey handshake following.
871 Return:
872 ==========================================================================
874 void PeerPairMsg4Action(struct rt_rtmp_adapter *pAd,
875 struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
877 struct rt_eapol_packet * pMsg4;
878 struct rt_header_802_11 * pHeader;
879 u32 MsgLen;
880 BOOLEAN Cancelled;
881 u8 group_cipher = Ndis802_11WEPDisabled;
883 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerPairMsg4Action\n"));
885 do {
886 if ((!pEntry) || (!pEntry->ValidAsCLI))
887 break;
889 if (Elem->MsgLen <
890 (LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H +
891 sizeof(struct rt_key_descripter) - MAX_LEN_OF_RSNIE - 2))
892 break;
894 if (pEntry->WpaState < AS_PTKINIT_NEGOTIATING)
895 break;
897 /* pointer to 802.11 header */
898 pHeader = (struct rt_header_802_11 *) Elem->Msg;
900 /* skip 802.11_header(24-byte) and LLC_header(8) */
901 pMsg4 =
902 (struct rt_eapol_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)
908 break;
910 /* 3. uses the MLME.SETKEYS.request to configure PTK into MAC */
911 NdisZeroMemory(&pEntry->PairwiseKey, sizeof(struct rt_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],
918 LEN_TKIP_EK);
919 NdisMoveMemory(pEntry->PairwiseKey.RxMic,
920 &pEntry->PTK[TKIP_AP_RXMICK_OFFSET],
921 LEN_TKIP_RXMICK);
922 NdisMoveMemory(pEntry->PairwiseKey.TxMic,
923 &pEntry->PTK[TKIP_AP_TXMICK_OFFSET],
924 LEN_TKIP_TXMICK);
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,
937 pEntry->Addr,
938 (u8)pEntry->Aid,
939 &pEntry->PairwiseKey);
941 /* update WCID attribute table and IVEIV table for this entry */
942 RTMPAddWcidAttributeEntry(pAd,
943 pEntry->apidx,
945 pEntry->PairwiseKey.CipherAlg,
946 pEntry);
949 /* 4. upgrade state */
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,
963 pEntry->Addr,
964 pEntry->apidx, 0);
966 DBGPRINT(RT_DEBUG_OFF,
967 ("AP SETKEYS DONE - WPA2, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
968 pEntry->AuthMode,
969 GetAuthMode(pEntry->AuthMode),
970 pEntry->WepStatus,
971 GetEncryptType(pEntry->WepStatus),
972 group_cipher, GetEncryptType(group_cipher)));
973 } else {
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);
981 } while (FALSE);
986 ==========================================================================
987 Description:
988 This is a function to send the first packet of 2-way groupkey handshake
989 Return:
991 ==========================================================================
993 void WPAStart2WayGroupHS(struct rt_rtmp_adapter *pAd, struct rt_mac_table_entry *pEntry)
995 u8 Header802_3[14];
996 u8 TxTsc[6];
997 struct rt_eapol_packet EAPOLPKT;
998 u8 group_cipher = Ndis802_11WEPDisabled;
999 u8 default_key = 0;
1000 u8 *gnonce_ptr = NULL;
1001 u8 *gtk_ptr = NULL;
1002 u8 *pBssid = NULL;
1004 DBGPRINT(RT_DEBUG_TRACE, ("===> WPAStart2WayGroupHS\n"));
1006 if ((!pEntry) || (!pEntry->ValidAsCLI))
1007 return;
1009 do {
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(struct rt_eapol_packet));
1015 ConstructEapolMsg(pEntry,
1016 group_cipher,
1017 EAPOL_GROUP_MSG_1,
1018 default_key,
1019 (u8 *) gnonce_ptr,
1020 TxTsc, (u8 *) 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 (u8 *)& EAPOLPKT,
1027 CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4,
1028 FALSE);
1030 } while (FALSE);
1032 DBGPRINT(RT_DEBUG_TRACE,
1033 ("<=== WPAStart2WayGroupHS : send out Group Message 1 \n"));
1035 return;
1039 ========================================================================
1041 Routine Description:
1042 Process Group key 2-way handshaking
1044 Arguments:
1045 pAd Pointer to our adapter
1046 Elem Message body
1048 Return Value:
1049 None
1051 Note:
1053 ========================================================================
1055 void PeerGroupMsg1Action(struct rt_rtmp_adapter *pAd,
1056 struct rt_mac_table_entry *pEntry, struct rt_mlme_queue_elem *Elem)
1058 u8 Header802_3[14];
1059 struct rt_eapol_packet EAPOLPKT;
1060 struct rt_eapol_packet * pGroup;
1061 u32 MsgLen;
1062 BOOLEAN Cancelled;
1063 u8 default_key = 0;
1064 u8 group_cipher = Ndis802_11WEPDisabled;
1065 u8 *pCurrentAddr = NULL;
1067 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerGroupMsg1Action \n"));
1069 if ((!pEntry) || ((!pEntry->ValidAsCLI) && (!pEntry->ValidAsApCli)))
1070 return;
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 = (struct rt_eapol_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)
1084 == FALSE)
1085 return;
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(struct rt_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 */
1100 0, &EAPOLPKT);
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 (u8 *)& EAPOLPKT,
1121 CONV_ARRARY_TO_u16(EAPOLPKT.Body_Len) + 4, FALSE);
1123 DBGPRINT(RT_DEBUG_TRACE,
1124 ("<=== PeerGroupMsg1Action: sned group message 2\n"));
1128 ==========================================================================
1129 Description:
1130 When receiving the last packet of 2-way groupkey handshake.
1131 Return:
1132 ==========================================================================
1134 void PeerGroupMsg2Action(struct rt_rtmp_adapter *pAd,
1135 struct rt_mac_table_entry *pEntry,
1136 void * Msg, u32 MsgLen)
1138 u32 Len;
1139 u8 *pData;
1140 BOOLEAN Cancelled;
1141 struct rt_eapol_packet * pMsg2;
1142 u8 group_cipher = Ndis802_11WEPDisabled;
1144 DBGPRINT(RT_DEBUG_TRACE, ("===> PeerGroupMsg2Action \n"));
1146 do {
1147 if ((!pEntry) || (!pEntry->ValidAsCLI))
1148 break;
1150 if (MsgLen <
1151 (LENGTH_802_1_H + LENGTH_EAPOL_H + sizeof(struct rt_key_descripter) -
1152 MAX_LEN_OF_RSNIE - 2))
1153 break;
1155 if (pEntry->WpaState != AS_PTKINITDONE)
1156 break;
1158 pData = (u8 *)Msg;
1159 pMsg2 = (struct rt_eapol_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)
1165 break;
1167 /* 3. upgrade state */
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,
1178 pEntry->Addr,
1179 pEntry->apidx, 0);
1181 DBGPRINT(RT_DEBUG_OFF,
1182 ("AP SETKEYS DONE - WPA2, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
1183 pEntry->AuthMode,
1184 GetAuthMode(pEntry->AuthMode),
1185 pEntry->WepStatus,
1186 GetEncryptType(pEntry->WepStatus),
1187 group_cipher, GetEncryptType(group_cipher)));
1188 } else {
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,
1193 pEntry->Addr,
1194 pEntry->apidx, 0);
1196 DBGPRINT(RT_DEBUG_OFF,
1197 ("AP SETKEYS DONE - WPA1, AuthMode(%d)=%s, WepStatus(%d)=%s, GroupWepStatus(%d)=%s\n\n",
1198 pEntry->AuthMode,
1199 GetAuthMode(pEntry->AuthMode),
1200 pEntry->WepStatus,
1201 GetEncryptType(pEntry->WepStatus),
1202 group_cipher, GetEncryptType(group_cipher)));
1204 } while (FALSE);
1208 ========================================================================
1210 Routine Description:
1211 Classify WPA EAP message type
1213 Arguments:
1214 EAPType Value of EAP message type
1215 MsgType Internal Message definition for MLME state machine
1217 Return Value:
1218 TRUE Found appropriate message type
1219 FALSE No appropriate message type
1221 IRQL = DISPATCH_LEVEL
1223 Note:
1224 All these constants are defined in wpa.h
1225 For supplicant, there is only EAPOL Key message avaliable
1227 ========================================================================
1229 BOOLEAN WpaMsgTypeSubst(u8 EAPType, int * MsgType)
1231 switch (EAPType) {
1232 case EAPPacket:
1233 *MsgType = MT2_EAPPacket;
1234 break;
1235 case EAPOLStart:
1236 *MsgType = MT2_EAPOLStart;
1237 break;
1238 case EAPOLLogoff:
1239 *MsgType = MT2_EAPOLLogoff;
1240 break;
1241 case EAPOLKey:
1242 *MsgType = MT2_EAPOLKey;
1243 break;
1244 case EAPOLASFAlert:
1245 *MsgType = MT2_EAPOLASFAlert;
1246 break;
1247 default:
1248 return FALSE;
1250 return TRUE;
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.
1263 Arguments:
1264 u8 *key, - the key material for HMAC_SHA1 use
1265 int key_len - the length of key
1266 u8 *prefix - a prefix label
1267 int prefix_len - the length of the label
1268 u8 *data - a specific data with variable length
1269 int data_len - the length of a specific data
1270 int len - the output lenght
1272 Return Value:
1273 u8 *output - the calculated result
1275 Note:
1276 802.11i-2004 Annex H.3
1278 ========================================================================
1280 void PRF(u8 * key,
1281 int key_len,
1282 u8 * prefix,
1283 int prefix_len,
1284 u8 * data, int data_len, u8 * output, int len)
1286 int i;
1287 u8 *input;
1288 int currentindex = 0;
1289 int total_len;
1291 /* Allocate memory for input */
1292 os_alloc_mem(NULL, (u8 **) & input, 1024);
1294 if (input == NULL) {
1295 DBGPRINT(RT_DEBUG_ERROR, ("PRF: no memory!\n"));
1296 return;
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;
1311 total_len++;
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],
1317 SHA1_DIGEST_SIZE);
1318 currentindex += 20;
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))
1329 * U2 = PRF(P, U1)
1330 * Uc = PRF(P, Uc-1)
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];
1337 int i, j;
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 */
1347 /* output = U1 */
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(char *password, u8 *ssid, int ssidlength, u8 *output)
1370 if ((strlen(password) > 63) || (ssidlength > 32))
1371 return 0;
1373 F(password, ssid, ssidlength, 4096, 1, output);
1374 F(password, ssid, ssidlength, 4096, 2, &output[SHA1_DIGEST_SIZE]);
1375 return 1;
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.
1385 Arguments:
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)
1394 Return Value:
1395 Output pointer to the PTK
1397 Note:
1398 Refer to IEEE 802.11i-2004 8.5.1.2
1400 ========================================================================
1402 void WpaDerivePTK(struct rt_rtmp_adapter *pAd,
1403 u8 * PMK,
1404 u8 * ANonce,
1405 u8 * AA,
1406 u8 * SNonce,
1407 u8 * SA, u8 * output, u32 len)
1409 u8 concatenation[76];
1410 u32 CurrPos = 0;
1411 u8 temp[32];
1412 u8 Prefix[] =
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);
1424 else
1425 NdisMoveMemory(concatenation, SA, 6);
1426 CurrPos += 6;
1428 /* Get larger address */
1429 if (RTMPCompareMemory(SA, AA, 6) == 1)
1430 NdisMoveMemory(&concatenation[CurrPos], SA, 6);
1431 else
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);
1437 CurrPos += 6;
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);
1444 else
1445 NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
1446 CurrPos += 32;
1448 /* Get larger Nonce */
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);
1453 else
1454 NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
1455 CurrPos += 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.
1470 Arguments:
1471 pAd - pointer to our pAdapter context
1472 macAddr - pointer to local MAC address
1474 Return Value:
1476 Note:
1477 802.1ii-2004 Annex H.5
1479 ========================================================================
1481 void GenRandom(struct rt_rtmp_adapter *pAd, u8 * macAddr, u8 * random)
1483 int i, curr;
1484 u8 local[80], KeyCounter[32];
1485 u8 result[80];
1486 unsigned long CurrentTime;
1487 u8 prefix[] =
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);
1507 curr += 32;
1509 /* concatenate a variable */
1510 NdisMoveMemory(&local[curr], &i, 2);
1511 curr += 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.
1527 Arguments:
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
1534 Return Value:
1536 Note:
1538 ========================================================================
1540 static void RTMPMakeRsnIeCipher(struct rt_rtmp_adapter *pAd,
1541 u8 ElementID,
1542 u32 WepStatus,
1543 IN BOOLEAN bMixCipher,
1544 u8 FlexibleCipher,
1545 u8 *pRsnIe, u8 * rsn_len)
1547 u8 PairwiseCnt;
1549 *rsn_len = 0;
1551 /* decide WPA2 or WPA1 */
1552 if (ElementID == Wpa2Ie) {
1553 struct rt_rsnie2 *pRsnie_cipher = (struct rt_rsnie2 *)pRsnIe;
1555 /* Assign the verson as 1 */
1556 pRsnie_cipher->version = 1;
1558 switch (WepStatus) {
1559 /* TKIP mode */
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,
1564 OUI_WPA2_TKIP, 4);
1565 *rsn_len = sizeof(struct rt_rsnie2);
1566 break;
1568 /* AES mode */
1569 case Ndis802_11Encryption3Enabled:
1570 if (bMixCipher)
1571 NdisMoveMemory(pRsnie_cipher->mcast,
1572 OUI_WPA2_TKIP, 4);
1573 else
1574 NdisMoveMemory(pRsnie_cipher->mcast,
1575 OUI_WPA2_CCMP, 4);
1576 pRsnie_cipher->ucount = 1;
1577 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1578 OUI_WPA2_CCMP, 4);
1579 *rsn_len = sizeof(struct rt_rsnie2);
1580 break;
1582 /* TKIP-AES mix mode */
1583 case Ndis802_11Encryption4Enabled:
1584 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
1586 PairwiseCnt = 1;
1587 /* Insert WPA2 TKIP as the first pairwise cipher */
1588 if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) {
1589 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1590 OUI_WPA2_TKIP, 4);
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,
1596 PairwiseCnt = 2;
1598 } else {
1599 /* Insert WPA2 AES as the first pairwise cipher */
1600 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1601 OUI_WPA2_CCMP, 4);
1604 pRsnie_cipher->ucount = PairwiseCnt;
1605 *rsn_len = sizeof(struct rt_rsnie2) + (4 * (PairwiseCnt - 1));
1606 break;
1609 if ((pAd->OpMode == OPMODE_STA) &&
1610 (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) &&
1611 (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) {
1612 u32 GroupCipher = pAd->StaCfg.GroupCipher;
1613 switch (GroupCipher) {
1614 case Ndis802_11GroupWEP40Enabled:
1615 NdisMoveMemory(pRsnie_cipher->mcast,
1616 OUI_WPA2_WEP40, 4);
1617 break;
1618 case Ndis802_11GroupWEP104Enabled:
1619 NdisMoveMemory(pRsnie_cipher->mcast,
1620 OUI_WPA2_WEP104, 4);
1621 break;
1624 /* swap for big-endian platform */
1625 pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
1626 pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
1627 } else {
1628 struct rt_rsnie *pRsnie_cipher = (struct rt_rsnie *)pRsnIe;
1630 /* Assign OUI and version */
1631 NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4);
1632 pRsnie_cipher->version = 1;
1634 switch (WepStatus) {
1635 /* TKIP mode */
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,
1640 OUI_WPA_TKIP, 4);
1641 *rsn_len = sizeof(struct rt_rsnie);
1642 break;
1644 /* AES mode */
1645 case Ndis802_11Encryption3Enabled:
1646 if (bMixCipher)
1647 NdisMoveMemory(pRsnie_cipher->mcast,
1648 OUI_WPA_TKIP, 4);
1649 else
1650 NdisMoveMemory(pRsnie_cipher->mcast,
1651 OUI_WPA_CCMP, 4);
1652 pRsnie_cipher->ucount = 1;
1653 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1654 OUI_WPA_CCMP, 4);
1655 *rsn_len = sizeof(struct rt_rsnie);
1656 break;
1658 /* TKIP-AES mix mode */
1659 case Ndis802_11Encryption4Enabled:
1660 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
1662 PairwiseCnt = 1;
1663 /* Insert WPA TKIP as the first pairwise cipher */
1664 if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) {
1665 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1666 OUI_WPA_TKIP, 4);
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,
1672 PairwiseCnt = 2;
1674 } else {
1675 /* Insert WPA AES as the first pairwise cipher */
1676 NdisMoveMemory(pRsnie_cipher->ucast[0].oui,
1677 OUI_WPA_CCMP, 4);
1680 pRsnie_cipher->ucount = PairwiseCnt;
1681 *rsn_len = sizeof(struct rt_rsnie) + (4 * (PairwiseCnt - 1));
1682 break;
1685 if ((pAd->OpMode == OPMODE_STA) &&
1686 (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) &&
1687 (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) {
1688 u32 GroupCipher = pAd->StaCfg.GroupCipher;
1689 switch (GroupCipher) {
1690 case Ndis802_11GroupWEP40Enabled:
1691 NdisMoveMemory(pRsnie_cipher->mcast,
1692 OUI_WPA_WEP40, 4);
1693 break;
1694 case Ndis802_11GroupWEP104Enabled:
1695 NdisMoveMemory(pRsnie_cipher->mcast,
1696 OUI_WPA_WEP104, 4);
1697 break;
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.
1713 Arguments:
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
1719 Return Value:
1721 Note:
1723 ========================================================================
1725 static void RTMPMakeRsnIeAKM(struct rt_rtmp_adapter *pAd,
1726 u8 ElementID,
1727 u32 AuthMode,
1728 u8 apidx,
1729 u8 *pRsnIe, u8 * rsn_len)
1731 struct rt_rsnie_auth *pRsnie_auth;
1732 u8 AkmCnt = 1; /* default as 1 */
1734 pRsnie_auth = (struct rt_rsnie_auth *) (pRsnIe + (*rsn_len));
1736 /* decide WPA2 or WPA1 */
1737 if (ElementID == Wpa2Ie) {
1739 switch (AuthMode) {
1740 case Ndis802_11AuthModeWPA2:
1741 case Ndis802_11AuthModeWPA1WPA2:
1742 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1743 OUI_WPA2_8021X_AKM, 4);
1744 break;
1746 case Ndis802_11AuthModeWPA2PSK:
1747 case Ndis802_11AuthModeWPA1PSKWPA2PSK:
1748 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1749 OUI_WPA2_PSK_AKM, 4);
1750 break;
1751 default:
1752 AkmCnt = 0;
1753 break;
1756 } else {
1757 switch (AuthMode) {
1758 case Ndis802_11AuthModeWPA:
1759 case Ndis802_11AuthModeWPA1WPA2:
1760 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1761 OUI_WPA_8021X_AKM, 4);
1762 break;
1764 case Ndis802_11AuthModeWPAPSK:
1765 case Ndis802_11AuthModeWPA1PSKWPA2PSK:
1766 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1767 OUI_WPA_PSK_AKM, 4);
1768 break;
1770 case Ndis802_11AuthModeWPANone:
1771 NdisMoveMemory(pRsnie_auth->auth[0].oui,
1772 OUI_WPA_NONE_AKM, 4);
1773 break;
1774 default:
1775 AkmCnt = 0;
1776 break;
1780 pRsnie_auth->acount = AkmCnt;
1781 pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount);
1783 /* update current RSNIE length */
1784 (*rsn_len) += (sizeof(struct rt_rsnie_auth) + (4 * (AkmCnt - 1)));
1789 ========================================================================
1791 Routine Description:
1792 Build capability in RSN-IE.
1793 It only shall be called by RTMPMakeRSNIE.
1795 Arguments:
1796 pAd - pointer to our pAdapter context
1797 ElementID - indicate the WPA1 or WPA2
1798 apidx - indicate the interface index
1800 Return Value:
1802 Note:
1804 ========================================================================
1806 static void RTMPMakeRsnIeCap(struct rt_rtmp_adapter *pAd,
1807 u8 ElementID,
1808 u8 apidx,
1809 u8 *pRsnIe, u8 * rsn_len)
1811 RSN_CAPABILITIES *pRSN_Cap;
1813 /* it could be ignored in WPA1 mode */
1814 if (ElementID == WpaIe)
1815 return;
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.
1831 Arguments:
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
1837 Return Value:
1839 Note:
1841 ========================================================================
1843 void RTMPMakeRSNIE(struct rt_rtmp_adapter *pAd,
1844 u32 AuthMode, u32 WepStatus, u8 apidx)
1846 u8 *pRsnIe = NULL; /* primary RSNIE */
1847 u8 *rsnielen_cur_p = 0; /* the length of the primary RSNIE */
1848 u8 *rsnielen_ex_cur_p = 0; /* the length of the secondary RSNIE */
1849 u8 PrimaryRsnie;
1850 BOOLEAN bMixCipher = FALSE; /* indicate the pairwise and group cipher are different */
1851 u8 p_offset;
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)
1862 return;
1863 } else {
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)
1870 return;
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);
1879 /* Pointer to 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;
1894 else
1895 PrimaryRsnie = Wpa2Ie;
1898 /* Build the primary RSNIE */
1899 /* 1. insert cipher suite */
1900 RTMPMakeRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher,
1901 FlexibleCipher, pRsnIe, &p_offset);
1903 /* 2. insert AKM */
1904 RTMPMakeRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe,
1905 &p_offset);
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 ==========================================================================
1920 Description:
1921 Check whether the received frame is EAP frame.
1923 Arguments:
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
1930 Return:
1931 TRUE - This frame is EAP frame
1932 FALSE - otherwise
1933 ==========================================================================
1935 BOOLEAN RTMPCheckWPAframe(struct rt_rtmp_adapter *pAd,
1936 struct rt_mac_table_entry *pEntry,
1937 u8 *pData,
1938 unsigned long DataByteCount, u8 FromWhichBSSID)
1940 unsigned long Body_len;
1941 BOOLEAN Cancelled;
1943 if (DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H))
1944 return FALSE;
1946 /* Skip LLC header */
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)) {
1950 pData += 6;
1952 /* Skip 2-bytes EAPoL type */
1953 if (NdisEqualMemory(EAPOL, pData, 2)) {
1954 pData += 2;
1955 } else
1956 return FALSE;
1958 switch (*(pData + 1)) {
1959 case EAPPacket:
1960 Body_len = (*(pData + 2) << 8) | (*(pData + 3));
1961 DBGPRINT(RT_DEBUG_TRACE,
1962 ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n",
1963 Body_len));
1964 break;
1965 case EAPOLStart:
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,
1973 &Cancelled);
1974 pEntry->EnqueueEapolStartTimerRunning =
1975 EAPOL_START_DISABLE;
1977 break;
1978 case EAPOLLogoff:
1979 DBGPRINT(RT_DEBUG_TRACE,
1980 ("Receive EAPOLLogoff frame, TYPE = 2 \n"));
1981 break;
1982 case EAPOLKey:
1983 Body_len = (*(pData + 2) << 8) | (*(pData + 3));
1984 DBGPRINT(RT_DEBUG_TRACE,
1985 ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n",
1986 Body_len));
1987 break;
1988 case EAPOLASFAlert:
1989 DBGPRINT(RT_DEBUG_TRACE,
1990 ("Receive EAPOLASFAlert frame, TYPE = 4 \n"));
1991 break;
1992 default:
1993 return FALSE;
1996 return TRUE;
2000 ==========================================================================
2001 Description:
2002 Report the EAP message type
2004 Arguments:
2005 msg - EAPOL_PAIR_MSG_1
2006 EAPOL_PAIR_MSG_2
2007 EAPOL_PAIR_MSG_3
2008 EAPOL_PAIR_MSG_4
2009 EAPOL_GROUP_MSG_1
2010 EAPOL_GROUP_MSG_2
2012 Return:
2013 message type string
2015 ==========================================================================
2017 char *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";
2031 else
2032 return "Invalid Message";
2036 ========================================================================
2038 Routine Description:
2039 Check Sanity RSN IE of EAPoL message
2041 Arguments:
2043 Return Value:
2045 ========================================================================
2047 BOOLEAN RTMPCheckRSNIE(struct rt_rtmp_adapter *pAd,
2048 u8 *pData,
2049 u8 DataLen,
2050 struct rt_mac_table_entry *pEntry, u8 * Offset)
2052 u8 *pVIE;
2053 u8 len;
2054 struct rt_eid * pEid;
2055 BOOLEAN result = FALSE;
2057 pVIE = pData;
2058 len = DataLen;
2059 *Offset = 0;
2061 while (len > sizeof(struct rt_rsnie2)) {
2062 pEid = (struct rt_eid *) pVIE;
2063 /* WPA RSN IE */
2064 if ((pEid->Eid == IE_WPA)
2065 && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) {
2066 if ((pEntry->AuthMode == Ndis802_11AuthModeWPA
2067 || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK)
2069 (NdisEqualMemory
2070 (pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len))
2071 && (pEntry->RSNIE_Len == (pEid->Len + 2))) {
2072 result = TRUE;
2075 *Offset += (pEid->Len + 2);
2077 /* WPA2 RSN IE */
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)
2085 (NdisEqualMemory
2086 (pEid->Octet, &pEntry->RSN_IE[2],
2087 pEntry->RSNIE_Len - 2))) {
2089 result = TRUE;
2092 *Offset += (pEid->Len + 2);
2093 } else {
2094 break;
2097 pVIE += (pEid->Len + 2);
2098 len -= (pEid->Len + 2);
2101 return result;
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
2112 Arguments:
2114 Return Value:
2116 Note:
2117 802.11i D10
2119 ========================================================================
2121 BOOLEAN RTMPParseEapolKeyData(struct rt_rtmp_adapter *pAd,
2122 u8 *pKeyData,
2123 u8 KeyDataLen,
2124 u8 GroupKeyIndex,
2125 u8 MsgType,
2126 IN BOOLEAN bWPA2, struct rt_mac_table_entry *pEntry)
2128 struct rt_kde_encap * pKDE = NULL;
2129 u8 *pMyKeyData = pKeyData;
2130 u8 KeyDataLength = KeyDataLen;
2131 u8 GTKLEN = 0;
2132 u8 DefaultIdx = 0;
2133 u8 skip_offset;
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 */
2138 if (!RTMPCheckRSNIE
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,
2144 pEntry->Addr,
2145 pEntry->apidx, 0);
2147 DBGPRINT(RT_DEBUG_ERROR,
2148 ("RSN_IE Different in msg %d of 4-way handshake!\n",
2149 MsgType));
2150 hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen);
2151 hex_dump("Desired RSN_IE ", pEntry->RSN_IE,
2152 pEntry->RSNIE_Len);
2154 return FALSE;
2155 } else {
2156 if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3) {
2157 WpaShowAllsuite(pMyKeyData, skip_offset);
2159 /* skip RSN IE */
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",
2164 skip_offset));
2165 } else
2166 return TRUE;
2170 DBGPRINT(RT_DEBUG_TRACE,
2171 ("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n",
2172 KeyDataLength));
2173 /*hex_dump("remain data", pMyKeyData, KeyDataLength); */
2175 /* Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2 */
2176 if (bWPA2
2177 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1)) {
2178 if (KeyDataLength >= 8) /* KDE format exclude GTK length */
2180 pKDE = (struct rt_kde_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"));
2188 return FALSE;
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",
2195 GTKLEN));
2196 return FALSE;
2199 } else {
2200 DBGPRINT(RT_DEBUG_ERROR,
2201 ("ERROR: KDE format length is too short \n"));
2202 return FALSE;
2205 DBGPRINT(RT_DEBUG_TRACE,
2206 ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n",
2207 DefaultIdx, GTKLEN));
2208 /* skip it */
2209 pMyKeyData += 8;
2210 KeyDataLength -= 8;
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)));
2223 return FALSE;
2227 struct rt_cipher_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(struct rt_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],
2240 LEN_TKIP_RXMICK);
2241 NdisMoveMemory(pSharedKey->TxMic, &pAd->StaCfg.GTK[24],
2242 LEN_TKIP_TXMICK);
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,
2259 BSS0,
2260 pAd->StaCfg.DefaultKeyId,
2261 pSharedKey->CipherAlg,
2262 pSharedKey->Key,
2263 pSharedKey->TxMic, pSharedKey->RxMic);
2265 /* Update ASIC WCID attribute table and IVEIV table */
2266 RTMPAddWcidAttributeEntry(pAd,
2267 BSS0,
2268 pAd->StaCfg.DefaultKeyId,
2269 pSharedKey->CipherAlg, NULL);
2272 return TRUE;
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 +--------------------+
2313 Arguments:
2314 pAd Pointer to our adapter
2316 Return Value:
2317 None
2319 Note:
2321 ========================================================================
2323 void ConstructEapolMsg(struct rt_mac_table_entry *pEntry,
2324 u8 GroupKeyWepStatus,
2325 u8 MsgType,
2326 u8 DefaultKeyIdx,
2327 u8 * KeyNonce,
2328 u8 * TxRSC,
2329 u8 * GTK,
2330 u8 * RSNIE,
2331 u8 RSNIE_Len, struct rt_eapol_packet * pMsg)
2333 BOOLEAN bWPA2 = FALSE;
2334 u8 KeyDescVer;
2336 /* Choose WPA2 or not */
2337 if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) ||
2338 (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK))
2339 bWPA2 = TRUE;
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_u16_TO_ARRARY(pMsg->Body_Len, LEN_EAPOL_KEY_MSG);
2348 /* Fill in EAPoL descriptor */
2349 if (bWPA2)
2350 pMsg->KeyDesc.Type = WPA2_KEY_DESC;
2351 else
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. */
2358 KeyDescVer =
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;
2370 else
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 *(u16 *) (&pMsg->KeyDesc.KeyInfo) =
2398 cpu2le16(*(u16 *) (&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 :
2407 LEN_AES_KEY);
2408 } else {
2409 /* the length of pairwise key cipher */
2410 pMsg->KeyDesc.KeyLength[1] =
2411 ((pEntry->WepStatus ==
2412 Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY :
2413 LEN_AES_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],
2434 LEN_KEY_DESC_IV);
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,
2447 GroupKeyWepStatus,
2448 KeyDescVer,
2449 MsgType,
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_u16(pMsg->Body_Len)));
2463 DBGPRINT(RT_DEBUG_TRACE,
2464 (" Key length = %d \n",
2465 CONV_ARRARY_TO_u16(pMsg->KeyDesc.KeyLength)));
2470 ========================================================================
2472 Routine Description:
2473 Construct the Key Data field of EAPoL message
2475 Arguments:
2476 pAd Pointer to our adapter
2477 Elem Message body
2479 Return Value:
2480 None
2482 Note:
2484 ========================================================================
2486 void ConstructEapolKeyData(struct rt_mac_table_entry *pEntry,
2487 u8 GroupKeyWepStatus,
2488 u8 keyDescVer,
2489 u8 MsgType,
2490 u8 DefaultKeyIdx,
2491 u8 * GTK,
2492 u8 * RSNIE,
2493 u8 RSNIE_LEN, struct rt_eapol_packet * pMsg)
2495 u8 *mpool, *Key_Data, *Rc4GTK;
2496 u8 ekey[(LEN_KEY_DESC_IV + LEN_EAP_EK)];
2497 unsigned long data_offset;
2498 BOOLEAN bWPA2Capable = FALSE;
2499 struct rt_rtmp_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)
2509 return;
2511 /* allocate memory pool */
2512 os_alloc_mem(NULL, (u8 **) & mpool, 1500);
2514 if (mpool == NULL)
2515 return;
2517 /* Rc4GTK Len = 512 */
2518 Rc4GTK = (u8 *) ROUND_UP(mpool, 4);
2519 /* Key_Data Len = 512 */
2520 Key_Data = (u8 *) ROUND_UP(Rc4GTK + 512, 4);
2522 NdisZeroMemory(Key_Data, 512);
2523 SET_u16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, 0);
2524 data_offset = 0;
2526 /* Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3 */
2527 if (RSNIE_LEN
2528 && ((MsgType == EAPOL_PAIR_MSG_2)
2529 || (MsgType == EAPOL_PAIR_MSG_3))) {
2530 u8 *pmkid_ptr = NULL;
2531 u8 pmkid_len = 0;
2533 RTMPInsertRSNIE(&Key_Data[data_offset],
2534 &data_offset,
2535 RSNIE, RSNIE_LEN, pmkid_ptr, pmkid_len);
2538 /* Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2 */
2539 if (bWPA2Capable
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) */
2547 } else {
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 */
2560 data_offset += 8;
2563 /* Encapsulate GTK */
2564 /* Only for pairwise_msg3_WPA2 and group_msg1 */
2565 if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable)
2566 || (MsgType == EAPOL_GROUP_MSG_1)) {
2567 /* Fill in GTK */
2568 if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) {
2569 NdisMoveMemory(&Key_Data[data_offset], GTK,
2570 LEN_AES_KEY);
2571 data_offset += LEN_AES_KEY;
2572 } else {
2573 NdisMoveMemory(&Key_Data[data_offset], GTK,
2574 TKIP_GTK_LENGTH);
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 */
2583 if (GTK_Included) {
2584 /*hex_dump("GTK_Included", Key_Data, data_offset); */
2586 if ((keyDescVer == DESC_TYPE_AES)) {
2587 u8 remainder = 0;
2588 u8 pad_len = 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 */
2592 /* the derived PTK. */
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) {
2599 int i;
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 */
2612 data_offset += 8;
2613 } else {
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,
2623 LEN_KEY_DESC_IV);
2624 NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &pEntry->PTK[16],
2625 LEN_EAP_EK);
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,
2629 data_offset);
2630 WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK,
2631 Key_Data, data_offset);
2634 NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset);
2635 } else {
2636 NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset);
2639 /* Update key data length field and total body length */
2640 SET_u16_TO_ARRARY(pMsg->KeyDesc.KeyDataLen, data_offset);
2641 INC_u16_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.
2653 Arguments:
2654 pAd - pointer to our pAdapter context
2655 PeerWepStatus - indicate the encryption type
2657 Return Value:
2659 Note:
2661 ========================================================================
2663 static void CalculateMIC(u8 KeyDescVer,
2664 u8 * PTK, struct rt_eapol_packet * pMsg)
2666 u8 *OutBuffer;
2667 unsigned long FrameLen = 0;
2668 u8 mic[LEN_KEY_DESC_MIC];
2669 u8 digest[80];
2671 /* allocate memory for MIC calculation */
2672 os_alloc_mem(NULL, (u8 **) & OutBuffer, 512);
2674 if (OutBuffer == NULL) {
2675 DBGPRINT(RT_DEBUG_ERROR, ("CalculateMIC: no memory!\n"));
2676 return;
2678 /* make a frame for calculating MIC. */
2679 MakeOutgoingFrame(OutBuffer, &FrameLen,
2680 CONV_ARRARY_TO_u16(pMsg->Body_Len) + 4, pMsg,
2681 END_OF_ARGS);
2683 NdisZeroMemory(mic, sizeof(mic));
2685 /* Calculate MIC */
2686 if (KeyDescVer == DESC_TYPE_AES) {
2687 HMAC_SHA1(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, digest,
2688 SHA1_DIGEST_SIZE);
2689 NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC);
2690 } else {
2691 HMAC_MD5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, mic,
2692 MD5_DIGEST_SIZE);
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.
2707 Arguments:
2708 pAd - pointer to our pAdapter context
2709 PeerWepStatus - indicate the encryption type
2711 Return Value:
2712 NDIS_STATUS_SUCCESS - decryption successful
2713 NDIS_STATUS_FAILURE - decryption failure
2715 ========================================================================
2717 int RTMPSoftDecryptBroadCastData(struct rt_rtmp_adapter *pAd,
2718 struct rt_rx_blk *pRxBlk,
2719 IN NDIS_802_11_ENCRYPTION_STATUS
2720 GroupCipher, struct rt_cipher_key *pShard_key)
2722 struct rt_rxwi * pRxWI = pRxBlk->pRxWI;
2724 /* handle WEP decryption */
2725 if (GroupCipher == Ndis802_11Encryption1Enabled) {
2726 if (RTMPSoftDecryptWEP
2727 (pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount,
2728 pShard_key)) {
2730 /*Minus IV[4] & ICV[4] */
2731 pRxWI->MPDUtotalByteCount -= 8;
2732 } else {
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,
2743 pShard_key)) {
2745 /*Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV */
2746 pRxWI->MPDUtotalByteCount -= 20;
2747 } else {
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,
2758 pShard_key)) {
2760 /*8 bytes MIC, 8 bytes IV/EIV (CCMP Header) */
2761 pRxWI->MPDUtotalByteCount -= 16;
2762 } else {
2763 DBGPRINT(RT_DEBUG_ERROR,
2764 ("ERROR : RTMPSoftDecryptAES Failed\n"));
2765 /* give up this frame */
2766 return NDIS_STATUS_FAILURE;
2768 } else {
2769 /* give up this frame */
2770 return NDIS_STATUS_FAILURE;
2773 return NDIS_STATUS_SUCCESS;
2777 u8 *GetSuiteFromRSNIE(u8 *rsnie,
2778 u32 rsnie_len, u8 type, u8 * count)
2780 struct rt_eid * pEid;
2781 int len;
2782 u8 *pBuf;
2783 int offset = 0;
2784 struct rt_rsnie_auth *pAkm;
2785 u16 acount;
2786 BOOLEAN isWPA2 = FALSE;
2788 pEid = (struct rt_eid *) rsnie;
2789 len = rsnie_len - 2; /* exclude IE and length */
2790 pBuf = (u8 *)& pEid->Octet[0];
2792 /* set default value */
2793 *count = 0;
2795 /* Check length */
2796 if ((len <= 0) || (pEid->Len != len)) {
2797 DBGPRINT_ERR(("%s : The length is invalid\n", __func__));
2798 return NULL;
2800 /* Check WPA or WPA2 */
2801 if (pEid->Eid == IE_WPA) {
2802 struct rt_rsnie *pRsnie = (struct rt_rsnie *)pBuf;
2803 u16 ucount;
2805 if (len < sizeof(struct rt_rsnie)) {
2806 DBGPRINT_ERR(("%s : The length is too short for WPA\n",
2807 __func__));
2808 return NULL;
2810 /* Get the count of pairwise cipher */
2811 ucount = cpu2le16(pRsnie->ucount);
2812 if (ucount > 2) {
2813 DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount));
2814 return NULL;
2816 /* Get the group cipher */
2817 if (type == GROUP_SUITE) {
2818 *count = 1;
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",
2825 __func__, ucount));
2826 *count = ucount;
2827 return pRsnie->ucast[0].oui;
2830 offset = sizeof(struct rt_rsnie) + (4 * (ucount - 1));
2832 } else if (pEid->Eid == IE_RSN) {
2833 struct rt_rsnie2 *pRsnie = (struct rt_rsnie2 *)pBuf;
2834 u16 ucount;
2836 isWPA2 = TRUE;
2838 if (len < sizeof(struct rt_rsnie2)) {
2839 DBGPRINT_ERR(("%s : The length is too short for WPA2\n",
2840 __func__));
2841 return NULL;
2843 /* Get the count of pairwise cipher */
2844 ucount = cpu2le16(pRsnie->ucount);
2845 if (ucount > 2) {
2846 DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount));
2847 return NULL;
2849 /* Get the group cipher */
2850 if (type == GROUP_SUITE) {
2851 *count = 1;
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",
2858 __func__, ucount));
2859 *count = ucount;
2860 return pRsnie->ucast[0].oui;
2863 offset = sizeof(struct rt_rsnie2) + (4 * (ucount - 1));
2865 } else {
2866 DBGPRINT_ERR(("%s : Unknown IE (%d)\n", __func__, pEid->Eid));
2867 return NULL;
2870 /* skip group cipher and pairwise cipher suite */
2871 pBuf += offset;
2872 len -= offset;
2874 if (len < sizeof(struct rt_rsnie_auth)) {
2875 DBGPRINT_ERR(("%s : The length of RSNIE is too short\n",
2876 __func__));
2877 return NULL;
2879 /* pointer to AKM count */
2880 pAkm = (struct rt_rsnie_auth *)pBuf;
2882 /* Get the count of pairwise cipher */
2883 acount = cpu2le16(pAkm->acount);
2884 if (acount > 2) {
2885 DBGPRINT_ERR(("%s : The count(%d) of AKM is invlaid\n",
2886 __func__, acount));
2887 return NULL;
2889 /* Get the AKM suite */
2890 if (type == AKM_SUITE) {
2891 DBGPRINT(RT_DEBUG_TRACE, ("%s : The count of AKM is %d\n",
2892 __func__, acount));
2893 *count = acount;
2894 return pAkm->auth[0].oui;
2896 offset = sizeof(struct rt_rsnie_auth) + (4 * (acount - 1));
2898 pBuf += offset;
2899 len -= offset;
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);
2907 /* Get PMKID */
2908 if (type == PMKID_LIST) {
2909 *count = 1;
2910 return pBuf;
2912 } else {
2913 DBGPRINT_ERR(("%s : it can't get any more information beyond AKM \n", __func__));
2914 return NULL;
2917 *count = 0;
2918 /*DBGPRINT_ERR(("%s : The type(%d) doesn't support \n", __func__, type)); */
2919 return NULL;
2923 void WpaShowAllsuite(u8 *rsnie, u32 rsnie_len)
2925 u8 *pSuite = NULL;
2926 u8 count;
2928 hex_dump("RSNIE", rsnie, rsnie_len);
2930 /* group cipher */
2931 if ((pSuite =
2932 GetSuiteFromRSNIE(rsnie, rsnie_len, GROUP_SUITE,
2933 &count)) != NULL) {
2934 hex_dump("group cipher", pSuite, 4 * count);
2936 /* pairwise cipher */
2937 if ((pSuite =
2938 GetSuiteFromRSNIE(rsnie, rsnie_len, PAIRWISE_SUITE,
2939 &count)) != NULL) {
2940 hex_dump("pairwise cipher", pSuite, 4 * count);
2942 /* AKM */
2943 if ((pSuite =
2944 GetSuiteFromRSNIE(rsnie, rsnie_len, AKM_SUITE, &count)) != NULL) {
2945 hex_dump("AKM suite", pSuite, 4 * count);
2947 /* PMKID */
2948 if ((pSuite =
2949 GetSuiteFromRSNIE(rsnie, rsnie_len, PMKID_LIST, &count)) != NULL) {
2950 hex_dump("PMKID", pSuite, LEN_PMKID);
2955 void RTMPInsertRSNIE(u8 *pFrameBuf,
2956 unsigned long *pFrameLen,
2957 u8 *rsnie_ptr,
2958 u8 rsnie_len,
2959 u8 *pmkid_ptr, u8 pmkid_len)
2961 u8 *pTmpBuf;
2962 unsigned long TempLen = 0;
2963 u8 extra_len = 0;
2964 u16 pmk_count = 0;
2965 u8 ie_num;
2966 u8 total_len = 0;
2967 u8 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(u16)+ pmkid_len;
2975 pmk_count = (pmkid_len >> 4);
2976 pmk_count = cpu2le16(pmk_count);
2977 } else {
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) {
2984 ie_num = IE_WPA;
2985 total_len = rsnie_len;
2987 if (NdisEqualMemory(rsnie_ptr + 2, WPA2_OUI, sizeof(WPA2_OUI))) {
2988 ie_num = IE_RSN;
2989 total_len += extra_len;
2992 /* construct RSNIE body */
2993 MakeOutgoingFrame(pTmpBuf, &TempLen,
2994 1, &ie_num,
2995 1, &total_len,
2996 rsnie_len, rsnie_ptr, END_OF_ARGS);
2998 pTmpBuf += TempLen;
2999 *pFrameLen = *pFrameLen + TempLen;
3001 if (ie_num == IE_RSN) {
3002 /* Insert PMKID-List field */
3003 if (extra_len > 0) {
3004 MakeOutgoingFrame(pTmpBuf, &TempLen,
3005 2, &pmk_count,
3006 pmkid_len, pmkid_ptr,
3007 END_OF_ARGS);
3009 pTmpBuf += TempLen;
3010 *pFrameLen = *pFrameLen + TempLen;
3015 return;