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