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