Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[sfrench/cifs-2.6.git] / drivers / staging / rt2860 / common / cmm_wpa.c
1 /*
2  *************************************************************************
3  * Ralink Tech Inc.
4  * 5F., No.36, Taiyuan St., Jhubei City,
5  * Hsinchu County 302,
6  * Taiwan, R.O.C.
7  *
8  * (c) Copyright 2002-2007, Ralink Technology, Inc.
9  *
10  * This program is free software; you can redistribute it and/or modify  *
11  * it under the terms of the GNU General Public License as published by  *
12  * the Free Software Foundation; either version 2 of the License, or     *
13  * (at your option) any later version.                                   *
14  *                                                                       *
15  * This program is distributed in the hope that it will be useful,       *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  * GNU General Public License for more details.                          *
19  *                                                                       *
20  * You should have received a copy of the GNU General Public License     *
21  * along with this program; if not, write to the                         *
22  * Free Software Foundation, Inc.,                                       *
23  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
24  *                                                                       *
25  *************************************************************************
26
27         Module Name:
28         wpa.c
29
30         Abstract:
31
32         Revision History:
33         Who                     When                    What
34         --------        ----------              ----------------------------------------------
35         Jan     Lee             03-07-22                Initial
36         Paul Lin        03-11-28                Modify for supplicant
37 */
38 #include "../rt_config.h"
39 // WPA OUI
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};
48 // WPA2 OUI
49 UCHAR       OUI_WPA2_WEP40[4]   = {0x00, 0x0F, 0xAC, 0x01};
50 UCHAR       OUI_WPA2_TKIP[4]        = {0x00, 0x0F, 0xAC, 0x02};
51 UCHAR       OUI_WPA2_CCMP[4]        = {0x00, 0x0F, 0xAC, 0x04};
52 UCHAR       OUI_WPA2_8021X_AKM[4]   = {0x00, 0x0F, 0xAC, 0x01};
53 UCHAR       OUI_WPA2_PSK_AKM[4]         = {0x00, 0x0F, 0xAC, 0x02};
54 UCHAR       OUI_WPA2_WEP104[4]   = {0x00, 0x0F, 0xAC, 0x05};
55 // MSA OUI
56 UCHAR           OUI_MSA_8021X_AKM[4]    = {0x00, 0x0F, 0xAC, 0x05};             // Not yet final - IEEE 802.11s-D1.06
57 UCHAR           OUI_MSA_PSK_AKM[4]      = {0x00, 0x0F, 0xAC, 0x06};             // Not yet final - IEEE 802.11s-D1.06
58
59 /*
60         ========================================================================
61
62         Routine Description:
63                 The pseudo-random function(PRF) that hashes various inputs to
64                 derive a pseudo-random value. To add liveness to the pseudo-random
65                 value, a nonce should be one of the inputs.
66
67                 It is used to generate PTK, GTK or some specific random value.
68
69         Arguments:
70                 UCHAR   *key,           -       the key material for HMAC_SHA1 use
71                 INT             key_len         -       the length of key
72                 UCHAR   *prefix         -       a prefix label
73                 INT             prefix_len      -       the length of the label
74                 UCHAR   *data           -       a specific data with variable length
75                 INT             data_len        -       the length of a specific data
76                 INT             len                     -       the output lenght
77
78         Return Value:
79                 UCHAR   *output         -       the calculated result
80
81         Note:
82                 802.11i-2004    Annex H.3
83
84         ========================================================================
85 */
86 VOID    PRF(
87         IN      UCHAR   *key,
88         IN      INT             key_len,
89         IN      UCHAR   *prefix,
90         IN      INT             prefix_len,
91         IN      UCHAR   *data,
92         IN      INT             data_len,
93         OUT     UCHAR   *output,
94         IN      INT             len)
95 {
96         INT             i;
97     UCHAR   *input;
98         INT             currentindex = 0;
99         INT             total_len;
100
101         // Allocate memory for input
102         os_alloc_mem(NULL, (PUCHAR *)&input, 1024);
103
104     if (input == NULL)
105     {
106         DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n"));
107         return;
108     }
109
110         // Generate concatenation input
111         NdisMoveMemory(input, prefix, prefix_len);
112
113         // Concatenate a single octet containing 0
114         input[prefix_len] =     0;
115
116         // Concatenate specific data
117         NdisMoveMemory(&input[prefix_len + 1], data, data_len);
118         total_len =     prefix_len + 1 + data_len;
119
120         // Concatenate a single octet containing 0
121         // This octet shall be update later
122         input[total_len] = 0;
123         total_len++;
124
125         // Iterate to calculate the result by hmac-sha-1
126         // Then concatenate to last result
127         for     (i = 0; i <     (len + 19) / 20; i++)
128         {
129                 HMAC_SHA1(input, total_len,     key, key_len, &output[currentindex]);
130                 currentindex += 20;
131
132                 // update the last octet
133                 input[total_len - 1]++;
134         }
135     os_free_mem(NULL, input);
136 }
137
138 /*
139         ========================================================================
140
141         Routine Description:
142                 It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK.
143                 It shall be called by 4-way handshake processing.
144
145         Arguments:
146                 pAd     -       pointer to our pAdapter context
147                 PMK             -       pointer to PMK
148                 ANonce  -       pointer to ANonce
149                 AA              -       pointer to Authenticator Address
150                 SNonce  -       pointer to SNonce
151                 SA              -       pointer to Supplicant Address
152                 len             -       indicate the length of PTK (octet)
153
154         Return Value:
155                 Output          pointer to the PTK
156
157         Note:
158                 Refer to IEEE 802.11i-2004 8.5.1.2
159
160         ========================================================================
161 */
162 VOID WpaCountPTK(
163         IN      PRTMP_ADAPTER   pAd,
164         IN      UCHAR   *PMK,
165         IN      UCHAR   *ANonce,
166         IN      UCHAR   *AA,
167         IN      UCHAR   *SNonce,
168         IN      UCHAR   *SA,
169         OUT     UCHAR   *output,
170         IN      UINT    len)
171 {
172         UCHAR   concatenation[76];
173         UINT    CurrPos = 0;
174         UCHAR   temp[32];
175         UCHAR   Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ',
176                                                 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'};
177
178         // initiate the concatenation input
179         NdisZeroMemory(temp, sizeof(temp));
180         NdisZeroMemory(concatenation, 76);
181
182         // Get smaller address
183         if (RTMPCompareMemory(SA, AA, 6) == 1)
184                 NdisMoveMemory(concatenation, AA, 6);
185         else
186                 NdisMoveMemory(concatenation, SA, 6);
187         CurrPos += 6;
188
189         // Get larger address
190         if (RTMPCompareMemory(SA, AA, 6) == 1)
191                 NdisMoveMemory(&concatenation[CurrPos], SA, 6);
192         else
193                 NdisMoveMemory(&concatenation[CurrPos], AA, 6);
194
195         // store the larger mac address for backward compatible of
196         // ralink proprietary STA-key issue
197         NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN);
198         CurrPos += 6;
199
200         // Get smaller Nonce
201         if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
202                 NdisMoveMemory(&concatenation[CurrPos], temp, 32);      // patch for ralink proprietary STA-key issue
203         else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
204                 NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
205         else
206                 NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
207         CurrPos += 32;
208
209         // Get larger Nonce
210         if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
211                 NdisMoveMemory(&concatenation[CurrPos], temp, 32);      // patch for ralink proprietary STA-key issue
212         else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
213                 NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
214         else
215                 NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
216         CurrPos += 32;
217
218         hex_dump("concatenation=", concatenation, 76);
219
220         // Use PRF to generate PTK
221         PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len);
222
223 }
224
225 /*
226         ========================================================================
227
228         Routine Description:
229                 Generate random number by software.
230
231         Arguments:
232                 pAd             -       pointer to our pAdapter context
233                 macAddr -       pointer to local MAC address
234
235         Return Value:
236
237         Note:
238                 802.1ii-2004  Annex H.5
239
240         ========================================================================
241 */
242 VOID    GenRandom(
243         IN      PRTMP_ADAPTER   pAd,
244         IN      UCHAR                   *macAddr,
245         OUT     UCHAR                   *random)
246 {
247         INT             i, curr;
248         UCHAR   local[80], KeyCounter[32];
249         UCHAR   result[80];
250         ULONG   CurrentTime;
251         UCHAR   prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'};
252
253         // Zero the related information
254         NdisZeroMemory(result, 80);
255         NdisZeroMemory(local, 80);
256         NdisZeroMemory(KeyCounter, 32);
257
258         for     (i = 0; i <     32;     i++)
259         {
260                 // copy the local MAC address
261                 COPY_MAC_ADDR(local, macAddr);
262                 curr =  MAC_ADDR_LEN;
263
264                 // concatenate the current time
265                 NdisGetSystemUpTime(&CurrentTime);
266                 NdisMoveMemory(&local[curr],  &CurrentTime,     sizeof(CurrentTime));
267                 curr += sizeof(CurrentTime);
268
269                 // concatenate the last result
270                 NdisMoveMemory(&local[curr],  result, 32);
271                 curr += 32;
272
273                 // concatenate a variable
274                 NdisMoveMemory(&local[curr],  &i,  2);
275                 curr += 2;
276
277                 // calculate the result
278                 PRF(KeyCounter, 32, prefix,12, local, curr, result, 32);
279         }
280
281         NdisMoveMemory(random, result,  32);
282 }
283
284 /*
285         ========================================================================
286
287         Routine Description:
288                 Build cipher suite in RSN-IE.
289                 It only shall be called by RTMPMakeRSNIE.
290
291         Arguments:
292                 pAd                     -       pointer to our pAdapter context
293         ElementID       -       indicate the WPA1 or WPA2
294         WepStatus       -       indicate the encryption type
295                 bMixCipher      -       a boolean to indicate the pairwise cipher and group
296                                                 cipher are the same or not
297
298         Return Value:
299
300         Note:
301
302         ========================================================================
303 */
304 static VOID RTMPInsertRsnIeCipher(
305         IN  PRTMP_ADAPTER   pAd,
306         IN      UCHAR                   ElementID,
307         IN      UINT                    WepStatus,
308         IN      BOOLEAN                 bMixCipher,
309         IN      UCHAR                   FlexibleCipher,
310         OUT     PUCHAR                  pRsnIe,
311         OUT     UCHAR                   *rsn_len)
312 {
313         UCHAR   PairwiseCnt;
314
315         *rsn_len = 0;
316
317         // decide WPA2 or WPA1
318         if (ElementID == Wpa2Ie)
319         {
320                 RSNIE2  *pRsnie_cipher = (RSNIE2*)pRsnIe;
321
322                 // Assign the verson as 1
323                 pRsnie_cipher->version = 1;
324
325         switch (WepStatus)
326         {
327                 // TKIP mode
328             case Ndis802_11Encryption2Enabled:
329                 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
330                 pRsnie_cipher->ucount = 1;
331                 NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4);
332                 *rsn_len = sizeof(RSNIE2);
333                 break;
334
335                         // AES mode
336             case Ndis802_11Encryption3Enabled:
337                                 if (bMixCipher)
338                                         NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
339                                 else
340                                         NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4);
341                 pRsnie_cipher->ucount = 1;
342                 NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4);
343                 *rsn_len = sizeof(RSNIE2);
344                 break;
345
346                         // TKIP-AES mix mode
347             case Ndis802_11Encryption4Enabled:
348                 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4);
349
350                                 PairwiseCnt = 1;
351                                 // Insert WPA2 TKIP as the first pairwise cipher
352                                 if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher))
353                                 {
354                         NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4);
355                                         // Insert WPA2 AES as the secondary pairwise cipher
356                                         if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher))
357                                         {
358                                 NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA2_CCMP, 4);
359                                                 PairwiseCnt = 2;
360                                         }
361                                 }
362                                 else
363                                 {
364                                         // Insert WPA2 AES as the first pairwise cipher
365                                         NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4);
366                                 }
367
368                 pRsnie_cipher->ucount = PairwiseCnt;
369                 *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1));
370                 break;
371         }
372
373                 if ((pAd->OpMode == OPMODE_STA) &&
374                         (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) &&
375                         (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled))
376                 {
377                         UINT GroupCipher = pAd->StaCfg.GroupCipher;
378                         switch(GroupCipher)
379                         {
380                                 case Ndis802_11GroupWEP40Enabled:
381                                         NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP40, 4);
382                                         break;
383                                 case Ndis802_11GroupWEP104Enabled:
384                                         NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP104, 4);
385                                         break;
386                         }
387                 }
388
389                 // swap for big-endian platform
390                 pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
391             pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
392         }
393         else
394         {
395                 RSNIE   *pRsnie_cipher = (RSNIE*)pRsnIe;
396
397                 // Assign OUI and version
398                 NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4);
399         pRsnie_cipher->version = 1;
400
401                 switch (WepStatus)
402                 {
403                         // TKIP mode
404             case Ndis802_11Encryption2Enabled:
405                 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
406                 pRsnie_cipher->ucount = 1;
407                 NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4);
408                 *rsn_len = sizeof(RSNIE);
409                 break;
410
411                         // AES mode
412             case Ndis802_11Encryption3Enabled:
413                                 if (bMixCipher)
414                                         NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
415                                 else
416                                         NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4);
417                 pRsnie_cipher->ucount = 1;
418                 NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4);
419                 *rsn_len = sizeof(RSNIE);
420                 break;
421
422                         // TKIP-AES mix mode
423             case Ndis802_11Encryption4Enabled:
424                 NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4);
425
426                                 PairwiseCnt = 1;
427                                 // Insert WPA TKIP as the first pairwise cipher
428                                 if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher))
429                                 {
430                         NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4);
431                                         // Insert WPA AES as the secondary pairwise cipher
432                                         if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher))
433                                         {
434                                 NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA_CCMP, 4);
435                                                 PairwiseCnt = 2;
436                                         }
437                                 }
438                                 else
439                                 {
440                                         // Insert WPA AES as the first pairwise cipher
441                                         NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4);
442                                 }
443
444                 pRsnie_cipher->ucount = PairwiseCnt;
445                 *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1));
446                 break;
447         }
448
449                 if ((pAd->OpMode == OPMODE_STA) &&
450                         (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) &&
451                         (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled))
452                 {
453                         UINT GroupCipher = pAd->StaCfg.GroupCipher;
454                         switch(GroupCipher)
455                         {
456                                 case Ndis802_11GroupWEP40Enabled:
457                                         NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP40, 4);
458                                         break;
459                                 case Ndis802_11GroupWEP104Enabled:
460                                         NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP104, 4);
461                                         break;
462                         }
463                 }
464
465                 // swap for big-endian platform
466                 pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version);
467             pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount);
468         }
469 }
470
471 /*
472         ========================================================================
473
474         Routine Description:
475                 Build AKM suite in RSN-IE.
476                 It only shall be called by RTMPMakeRSNIE.
477
478         Arguments:
479                 pAd                     -       pointer to our pAdapter context
480         ElementID       -       indicate the WPA1 or WPA2
481         AuthMode        -       indicate the authentication mode
482                 apidx           -       indicate the interface index
483
484         Return Value:
485
486         Note:
487
488         ========================================================================
489 */
490 static VOID RTMPInsertRsnIeAKM(
491         IN  PRTMP_ADAPTER   pAd,
492         IN      UCHAR                   ElementID,
493         IN      UINT                    AuthMode,
494         IN      UCHAR                   apidx,
495         OUT     PUCHAR                  pRsnIe,
496         OUT     UCHAR                   *rsn_len)
497 {
498         RSNIE_AUTH              *pRsnie_auth;
499
500         pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len));
501
502         // decide WPA2 or WPA1
503         if (ElementID == Wpa2Ie)
504         {
505                 switch (AuthMode)
506         {
507             case Ndis802_11AuthModeWPA2:
508             case Ndis802_11AuthModeWPA1WPA2:
509                 pRsnie_auth->acount = 1;
510                         NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4);
511                 break;
512
513             case Ndis802_11AuthModeWPA2PSK:
514             case Ndis802_11AuthModeWPA1PSKWPA2PSK:
515                 pRsnie_auth->acount = 1;
516                         NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4);
517                 break;
518         }
519         }
520         else
521         {
522                 switch (AuthMode)
523         {
524             case Ndis802_11AuthModeWPA:
525             case Ndis802_11AuthModeWPA1WPA2:
526                 pRsnie_auth->acount = 1;
527                 NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4);
528                 break;
529
530             case Ndis802_11AuthModeWPAPSK:
531             case Ndis802_11AuthModeWPA1PSKWPA2PSK:
532                 pRsnie_auth->acount = 1;
533                 NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4);
534                 break;
535
536                         case Ndis802_11AuthModeWPANone:
537                 pRsnie_auth->acount = 1;
538                 NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4);
539                 break;
540         }
541         }
542
543         pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount);
544
545         (*rsn_len) += sizeof(RSNIE_AUTH);       // update current RSNIE length
546
547 }
548
549 /*
550         ========================================================================
551
552         Routine Description:
553                 Build capability in RSN-IE.
554                 It only shall be called by RTMPMakeRSNIE.
555
556         Arguments:
557                 pAd                     -       pointer to our pAdapter context
558         ElementID       -       indicate the WPA1 or WPA2
559                 apidx           -       indicate the interface index
560
561         Return Value:
562
563         Note:
564
565         ========================================================================
566 */
567 static VOID RTMPInsertRsnIeCap(
568         IN  PRTMP_ADAPTER   pAd,
569         IN      UCHAR                   ElementID,
570         IN      UCHAR                   apidx,
571         OUT     PUCHAR                  pRsnIe,
572         OUT     UCHAR                   *rsn_len)
573 {
574         RSN_CAPABILITIES    *pRSN_Cap;
575
576         // it could be ignored in WPA1 mode
577         if (ElementID == WpaIe)
578                 return;
579
580         pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len));
581
582
583         pRSN_Cap->word = cpu2le16(pRSN_Cap->word);
584
585         (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length
586
587 }
588
589
590 /*
591         ========================================================================
592
593         Routine Description:
594                 Build RSN IE context. It is not included element-ID and length.
595
596         Arguments:
597                 pAd                     -       pointer to our pAdapter context
598         AuthMode        -       indicate the authentication mode
599         WepStatus       -       indicate the encryption type
600                 apidx           -       indicate the interface index
601
602         Return Value:
603
604         Note:
605
606         ========================================================================
607 */
608 VOID RTMPMakeRSNIE(
609     IN  PRTMP_ADAPTER   pAd,
610     IN  UINT            AuthMode,
611     IN  UINT            WepStatus,
612         IN      UCHAR                   apidx)
613 {
614         PUCHAR          pRsnIe = NULL;                  // primary RSNIE
615         UCHAR           *rsnielen_cur_p = 0;    // the length of the primary RSNIE
616         UCHAR           *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE
617         UCHAR           PrimaryRsnie;
618         BOOLEAN         bMixCipher = FALSE;     // indicate the pairwise and group cipher are different
619         UCHAR           p_offset;
620         WPA_MIX_PAIR_CIPHER             FlexibleCipher = WPA_TKIPAES_WPA2_TKIPAES;      // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode
621
622         rsnielen_cur_p = NULL;
623         rsnielen_ex_cur_p = NULL;
624
625         {
626                 {
627                         if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE)
628                         {
629                                 if (AuthMode < Ndis802_11AuthModeWPA)
630                                         return;
631                         }
632                         else
633                         {
634                                 // Support WPAPSK or WPA2PSK in STA-Infra mode
635                                 // Support WPANone in STA-Adhoc mode
636                                 if ((AuthMode != Ndis802_11AuthModeWPAPSK) &&
637                                         (AuthMode != Ndis802_11AuthModeWPA2PSK) &&
638                                         (AuthMode != Ndis802_11AuthModeWPANone)
639                                         )
640                                         return;
641                         }
642
643                         DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n"));
644
645                         // Zero RSNIE context
646                         pAd->StaCfg.RSNIE_Len = 0;
647                         NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE);
648
649                         // Pointer to RSNIE
650                         rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len;
651                         pRsnIe = pAd->StaCfg.RSN_IE;
652
653                         bMixCipher = pAd->StaCfg.bMixCipher;
654                 }
655         }
656
657         // indicate primary RSNIE as WPA or WPA2
658         if ((AuthMode == Ndis802_11AuthModeWPA) ||
659                 (AuthMode == Ndis802_11AuthModeWPAPSK) ||
660                 (AuthMode == Ndis802_11AuthModeWPANone) ||
661                 (AuthMode == Ndis802_11AuthModeWPA1WPA2) ||
662                 (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK))
663                 PrimaryRsnie = WpaIe;
664         else
665                 PrimaryRsnie = Wpa2Ie;
666
667         {
668                 // Build the primary RSNIE
669                 // 1. insert cipher suite
670                 RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset);
671
672                 // 2. insert AKM
673                 RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset);
674
675                 // 3. insert capability
676                 RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset);
677         }
678
679         // 4. update the RSNIE length
680         *rsnielen_cur_p = p_offset;
681
682         hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p));
683
684
685 }
686
687 /*
688     ==========================================================================
689     Description:
690                 Check whether the received frame is EAP frame.
691
692         Arguments:
693                 pAd                             -       pointer to our pAdapter context
694                 pEntry                  -       pointer to active entry
695                 pData                   -       the received frame
696                 DataByteCount   -       the received frame's length
697                 FromWhichBSSID  -       indicate the interface index
698
699     Return:
700          TRUE                   -       This frame is EAP frame
701          FALSE                  -       otherwise
702     ==========================================================================
703 */
704 BOOLEAN RTMPCheckWPAframe(
705     IN PRTMP_ADAPTER    pAd,
706     IN PMAC_TABLE_ENTRY pEntry,
707     IN PUCHAR           pData,
708     IN ULONG            DataByteCount,
709         IN UCHAR                        FromWhichBSSID)
710 {
711         ULONG   Body_len;
712         BOOLEAN Cancelled;
713
714
715     if(DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H))
716         return FALSE;
717
718
719         // Skip LLC header
720     if (NdisEqualMemory(SNAP_802_1H, pData, 6) ||
721         // Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL
722         NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6))
723     {
724         pData += 6;
725     }
726         // Skip 2-bytes EAPoL type
727     if (NdisEqualMemory(EAPOL, pData, 2))
728     {
729         pData += 2;
730     }
731     else
732         return FALSE;
733
734     switch (*(pData+1))
735     {
736         case EAPPacket:
737                         Body_len = (*(pData+2)<<8) | (*(pData+3));
738             DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len));
739             break;
740         case EAPOLStart:
741             DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n"));
742                         if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE)
743             {
744                 DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n"));
745                 RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled);
746                 pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE;
747             }
748             break;
749         case EAPOLLogoff:
750             DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n"));
751             break;
752         case EAPOLKey:
753                         Body_len = (*(pData+2)<<8) | (*(pData+3));
754             DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len));
755             break;
756         case EAPOLASFAlert:
757             DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n"));
758             break;
759         default:
760             return FALSE;
761
762     }
763     return TRUE;
764 }
765
766 /*
767         ========================================================================
768
769         Routine Description:
770                 Misc function to decrypt AES body
771
772         Arguments:
773
774         Return Value:
775
776         Note:
777                 This function references to     RFC     3394 for aes key unwrap algorithm.
778
779         ========================================================================
780 */
781 VOID    AES_GTK_KEY_UNWRAP(
782         IN      UCHAR   *key,
783         OUT     UCHAR   *plaintext,
784         IN      UCHAR    c_len,
785         IN      UCHAR   *ciphertext)
786
787 {
788         UCHAR       A[8], BIN[16], BOUT[16];
789         UCHAR       xor;
790         INT         i, j;
791         aes_context aesctx;
792         UCHAR       *R;
793         INT         num_blocks = c_len/8;       // unit:64bits
794
795
796         os_alloc_mem(NULL, (PUCHAR *)&R, 512);
797
798         if (R == NULL)
799     {
800         DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n"));
801         return;
802     } /* End of if */
803
804         // Initialize
805         NdisMoveMemory(A, ciphertext, 8);
806         //Input plaintext
807         for(i = 0; i < (c_len-8); i++)
808         {
809                 R[ i] = ciphertext[i + 8];
810         }
811
812         rtmp_aes_set_key(&aesctx, key, 128);
813
814         for(j = 5; j >= 0; j--)
815         {
816                 for(i = (num_blocks-1); i > 0; i--)
817                 {
818                         xor = (num_blocks -1 )* j + i;
819                         NdisMoveMemory(BIN, A, 8);
820                         BIN[7] = A[7] ^ xor;
821                         NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8);
822                         rtmp_aes_decrypt(&aesctx, BIN, BOUT);
823                         NdisMoveMemory(A, &BOUT[0], 8);
824                         NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8);
825                 }
826         }
827
828         // OUTPUT
829         for(i = 0; i < c_len; i++)
830         {
831                 plaintext[i] = R[i];
832         }
833
834
835         os_free_mem(NULL, R);
836 }