Merge tag 'v3.10.79' into linux-linaro-lsk-v3.10
[firefly-linux-kernel-4.4.55.git] / drivers / staging / vt6655 / wpa2.c
1 /*
2  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  *
20  * File: wpa2.c
21  *
22  * Purpose: Handles the Basic Service Set & Node Database functions
23  *
24  * Functions:
25  *
26  * Revision History:
27  *
28  * Author: Yiching Chen
29  *
30  * Date: Oct. 4, 2004
31  *
32  */
33
34 #include "wpa2.h"
35 #include "device.h"
36 #include "wmgr.h"
37
38 /*---------------------  Static Definitions -------------------------*/
39 static int msglevel = MSG_LEVEL_INFO;
40 //static int          msglevel                =MSG_LEVEL_DEBUG;
41 /*---------------------  Static Classes  ----------------------------*/
42
43 /*---------------------  Static Variables  --------------------------*/
44
45 const unsigned char abyOUIGK[4]      = { 0x00, 0x0F, 0xAC, 0x00 };
46 const unsigned char abyOUIWEP40[4]   = { 0x00, 0x0F, 0xAC, 0x01 };
47 const unsigned char abyOUIWEP104[4]  = { 0x00, 0x0F, 0xAC, 0x05 };
48 const unsigned char abyOUITKIP[4]    = { 0x00, 0x0F, 0xAC, 0x02 };
49 const unsigned char abyOUICCMP[4]    = { 0x00, 0x0F, 0xAC, 0x04 };
50
51 const unsigned char abyOUI8021X[4]   = { 0x00, 0x0F, 0xAC, 0x01 };
52 const unsigned char abyOUIPSK[4]     = { 0x00, 0x0F, 0xAC, 0x02 };
53
54 /*---------------------  Static Functions  --------------------------*/
55
56 /*---------------------  Export Variables  --------------------------*/
57
58 /*---------------------  Export Functions  --------------------------*/
59
60 /*+
61  *
62  * Description:
63  *    Clear RSN information in BSSList.
64  *
65  * Parameters:
66  *  In:
67  *      pBSSNode - BSS list.
68  *  Out:
69  *      none
70  *
71  * Return Value: none.
72  *
73  -*/
74 void
75 WPA2_ClearRSN(
76         PKnownBSS        pBSSNode
77 )
78 {
79         int ii;
80
81         pBSSNode->bWPA2Valid = false;
82
83         pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
84         for (ii = 0; ii < 4; ii++)
85                 pBSSNode->abyCSSPK[ii] = WLAN_11i_CSS_CCMP;
86         pBSSNode->wCSSPKCount = 1;
87         for (ii = 0; ii < 4; ii++)
88                 pBSSNode->abyAKMSSAuthType[ii] = WLAN_11i_AKMSS_802_1X;
89         pBSSNode->wAKMSSAuthCount = 1;
90         pBSSNode->sRSNCapObj.bRSNCapExist = false;
91         pBSSNode->sRSNCapObj.wRSNCap = 0;
92 }
93
94 /*+
95  *
96  * Description:
97  *    Parse RSN IE.
98  *
99  * Parameters:
100  *  In:
101  *      pBSSNode - BSS list.
102  *      pRSN - Pointer to the RSN IE.
103  *  Out:
104  *      none
105  *
106  * Return Value: none.
107  *
108  -*/
109 void
110 WPA2vParseRSN(
111         PKnownBSS        pBSSNode,
112         PWLAN_IE_RSN     pRSN
113 )
114 {
115         int                 i, j;
116         unsigned short m = 0, n = 0;
117         unsigned char *pbyOUI;
118         bool bUseGK = false;
119
120         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WPA2_ParseRSN: [%d]\n", pRSN->len);
121
122         WPA2_ClearRSN(pBSSNode);
123
124         if (pRSN->len == 2) { // ver(2)
125                 if ((pRSN->byElementID == WLAN_EID_RSN) && (pRSN->wVersion == 1)) {
126                         pBSSNode->bWPA2Valid = true;
127                 }
128                 return;
129         }
130
131         if (pRSN->len < 6) { // ver(2) + GK(4)
132                 // invalid CSS, P802.11i/D10.0, p31
133                 return;
134         }
135
136         // information element header makes sense
137         if ((pRSN->byElementID == WLAN_EID_RSN) &&
138             (pRSN->wVersion == 1)) {
139                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Legal 802.11i RSN\n");
140
141                 pbyOUI = &(pRSN->abyRSN[0]);
142                 if (!memcmp(pbyOUI, abyOUIWEP40, 4))
143                         pBSSNode->byCSSGK = WLAN_11i_CSS_WEP40;
144                 else if (!memcmp(pbyOUI, abyOUITKIP, 4))
145                         pBSSNode->byCSSGK = WLAN_11i_CSS_TKIP;
146                 else if (!memcmp(pbyOUI, abyOUICCMP, 4))
147                         pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
148                 else if (!memcmp(pbyOUI, abyOUIWEP104, 4))
149                         pBSSNode->byCSSGK = WLAN_11i_CSS_WEP104;
150                 else if (!memcmp(pbyOUI, abyOUIGK, 4)) {
151                         // invalid CSS, P802.11i/D10.0, p32
152                         return;
153                 } else
154                         // any vendor checks here
155                         pBSSNode->byCSSGK = WLAN_11i_CSS_UNKNOWN;
156
157                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "802.11i CSS: %X\n", pBSSNode->byCSSGK);
158
159                 if (pRSN->len == 6) {
160                         pBSSNode->bWPA2Valid = true;
161                         return;
162                 }
163
164                 if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2)
165                         pBSSNode->wCSSPKCount = *((unsigned short *)&(pRSN->abyRSN[4]));
166                         j = 0;
167                         pbyOUI = &(pRSN->abyRSN[6]);
168
169                         for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(unsigned char)); i++) {
170                                 if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i)
171                                         if (!memcmp(pbyOUI, abyOUIGK, 4)) {
172                                                 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP;
173                                                 bUseGK = true;
174                                         } else if (!memcmp(pbyOUI, abyOUIWEP40, 4)) {
175                                                 // Invalid CSS, continue to parsing
176                                         } else if (!memcmp(pbyOUI, abyOUITKIP, 4)) {
177                                                 if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP)
178                                                         pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP;
179                                                 else
180                                                         ; // Invalid CSS, continue to parsing
181                                         } else if (!memcmp(pbyOUI, abyOUICCMP, 4)) {
182                                                 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP;
183                                         } else if (!memcmp(pbyOUI, abyOUIWEP104, 4)) {
184                                                 // Invalid CSS, continue to parsing
185                                         } else {
186                                                 // any vendor checks here
187                                                 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN;
188                                         }
189                                         pbyOUI += 4;
190                                         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "abyCSSPK[%d]: %X\n", j-1, pBSSNode->abyCSSPK[j-1]);
191                                 } else
192                                         break;
193                         } //for
194
195                         if (bUseGK == true) {
196                                 if (j != 1) {
197                                         // invalid CSS, This should be only PK CSS.
198                                         return;
199                                 }
200                                 if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) {
201                                         // invalid CSS, If CCMP is enable , PK can't be CSSGK.
202                                         return;
203                                 }
204                         }
205                         if ((pBSSNode->wCSSPKCount != 0) && (j == 0)) {
206                                 // invalid CSS, No valid PK.
207                                 return;
208                         }
209                         pBSSNode->wCSSPKCount = (unsigned short)j;
210                         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wCSSPKCount: %d\n", pBSSNode->wCSSPKCount);
211                 }
212
213                 m = *((unsigned short *)&(pRSN->abyRSN[4]));
214
215                 if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
216                         pBSSNode->wAKMSSAuthCount = *((unsigned short *)&(pRSN->abyRSN[6+4*m]));
217                         j = 0;
218                         pbyOUI = &(pRSN->abyRSN[8+4*m]);
219                         for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(unsigned char)); i++) {
220                                 if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i)
221                                         if (!memcmp(pbyOUI, abyOUI8021X, 4))
222                                                 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X;
223                                         else if (!memcmp(pbyOUI, abyOUIPSK, 4))
224                                                 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_PSK;
225                                         else
226                                                 // any vendor checks here
227                                                 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_UNKNOWN;
228                                         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "abyAKMSSAuthType[%d]: %X\n", j-1, pBSSNode->abyAKMSSAuthType[j-1]);
229                                 } else
230                                         break;
231                         }
232                         pBSSNode->wAKMSSAuthCount = (unsigned short)j;
233                         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount);
234
235                         n = *((unsigned short *)&(pRSN->abyRSN[6+4*m]));
236                         if (pRSN->len >= 12 + 4 * m + 4 * n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
237                                 pBSSNode->sRSNCapObj.bRSNCapExist = true;
238                                 pBSSNode->sRSNCapObj.wRSNCap = *((unsigned short *)&(pRSN->abyRSN[8+4*m+4*n]));
239                         }
240                 }
241                 //ignore PMKID lists bcs only (Re)Assocrequest has this field
242                 pBSSNode->bWPA2Valid = true;
243         }
244 }
245
246 /*+
247  *
248  * Description:
249  *    Set WPA IEs
250  *
251  * Parameters:
252  *  In:
253  *      pMgmtHandle - Pointer to management object
254  *  Out:
255  *      pRSNIEs     - Pointer to the RSN IE to set.
256  *
257  * Return Value: length of IEs.
258  *
259  -*/
260 unsigned int
261 WPA2uSetIEs(
262         void *pMgmtHandle,
263         PWLAN_IE_RSN pRSNIEs
264 )
265 {
266         PSMgmtObject    pMgmt = (PSMgmtObject) pMgmtHandle;
267         unsigned char *pbyBuffer = NULL;
268         unsigned int ii = 0;
269         unsigned short *pwPMKID = NULL;
270
271         if (pRSNIEs == NULL) {
272                 return 0;
273         }
274         if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
275              (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
276             (pMgmt->pCurrBSS != NULL)) {
277                 /* WPA2 IE */
278                 pbyBuffer = (unsigned char *)pRSNIEs;
279                 pRSNIEs->byElementID = WLAN_EID_RSN;
280                 pRSNIEs->len = 6; //Version(2)+GK(4)
281                 pRSNIEs->wVersion = 1;
282                 //Group Key Cipher Suite
283                 pRSNIEs->abyRSN[0] = 0x00;
284                 pRSNIEs->abyRSN[1] = 0x0F;
285                 pRSNIEs->abyRSN[2] = 0xAC;
286                 if (pMgmt->byCSSGK == KEY_CTL_WEP) {
287                         pRSNIEs->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
288                 } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
289                         pRSNIEs->abyRSN[3] = WLAN_11i_CSS_TKIP;
290                 } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
291                         pRSNIEs->abyRSN[3] = WLAN_11i_CSS_CCMP;
292                 } else {
293                         pRSNIEs->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
294                 }
295
296                 // Pairwise Key Cipher Suite
297                 pRSNIEs->abyRSN[4] = 1;
298                 pRSNIEs->abyRSN[5] = 0;
299                 pRSNIEs->abyRSN[6] = 0x00;
300                 pRSNIEs->abyRSN[7] = 0x0F;
301                 pRSNIEs->abyRSN[8] = 0xAC;
302                 if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
303                         pRSNIEs->abyRSN[9] = WLAN_11i_CSS_TKIP;
304                 } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
305                         pRSNIEs->abyRSN[9] = WLAN_11i_CSS_CCMP;
306                 } else if (pMgmt->byCSSPK == KEY_CTL_NONE) {
307                         pRSNIEs->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
308                 } else {
309                         pRSNIEs->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
310                 }
311                 pRSNIEs->len += 6;
312
313                 // Auth Key Management Suite
314                 pRSNIEs->abyRSN[10] = 1;
315                 pRSNIEs->abyRSN[11] = 0;
316                 pRSNIEs->abyRSN[12] = 0x00;
317                 pRSNIEs->abyRSN[13] = 0x0F;
318                 pRSNIEs->abyRSN[14] = 0xAC;
319                 if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) {
320                         pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_PSK;
321                 } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
322                         pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
323                 } else {
324                         pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
325                 }
326                 pRSNIEs->len += 6;
327
328                 // RSN Capabilities
329                 if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
330                         memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
331                 } else {
332                         pRSNIEs->abyRSN[16] = 0;
333                         pRSNIEs->abyRSN[17] = 0;
334                 }
335                 pRSNIEs->len += 2;
336
337                 if ((pMgmt->gsPMKIDCache.BSSIDInfoCount > 0) &&
338                     (pMgmt->bRoaming == true) &&
339                     (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
340                         // RSN PMKID
341                         pwPMKID = (unsigned short *)(&pRSNIEs->abyRSN[18]);  // Point to PMKID count
342                         *pwPMKID = 0;                               // Initialize PMKID count
343                         pbyBuffer = &pRSNIEs->abyRSN[20];           // Point to PMKID list
344                         for (ii = 0; ii < pMgmt->gsPMKIDCache.BSSIDInfoCount; ii++) {
345                                 if (!memcmp(&pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyBSSID[0], pMgmt->abyCurrBSSID, ETH_ALEN)) {
346                                         (*pwPMKID)++;
347                                         memcpy(pbyBuffer, pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyPMKID, 16);
348                                         pbyBuffer += 16;
349                                 }
350                         }
351                         if (*pwPMKID != 0) {
352                                 pRSNIEs->len += (2 + (*pwPMKID)*16);
353                         } else {
354                                 pbyBuffer = &pRSNIEs->abyRSN[18];
355                         }
356                 }
357                 return pRSNIEs->len + WLAN_IEHDR_LEN;
358         }
359         return 0;
360 }