Merge tag 'asoc-v3.18-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[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 Classes  ----------------------------*/
39
40 /*---------------------  Static Variables  --------------------------*/
41
42 static const unsigned char abyOUIGK[4]      = { 0x00, 0x0F, 0xAC, 0x00 };
43 static const unsigned char abyOUIWEP40[4]   = { 0x00, 0x0F, 0xAC, 0x01 };
44 static const unsigned char abyOUIWEP104[4]  = { 0x00, 0x0F, 0xAC, 0x05 };
45 static const unsigned char abyOUITKIP[4]    = { 0x00, 0x0F, 0xAC, 0x02 };
46 static const unsigned char abyOUICCMP[4]    = { 0x00, 0x0F, 0xAC, 0x04 };
47
48 static const unsigned char abyOUI8021X[4]   = { 0x00, 0x0F, 0xAC, 0x01 };
49 static const unsigned char abyOUIPSK[4]     = { 0x00, 0x0F, 0xAC, 0x02 };
50
51 /*---------------------  Static Functions  --------------------------*/
52
53 /*---------------------  Export Variables  --------------------------*/
54
55 /*---------------------  Export Functions  --------------------------*/
56
57 /*+
58  *
59  * Description:
60  *    Clear RSN information in BSSList.
61  *
62  * Parameters:
63  *  In:
64  *      pBSSNode - BSS list.
65  *  Out:
66  *      none
67  *
68  * Return Value: none.
69  *
70  -*/
71 void
72 WPA2_ClearRSN(
73         PKnownBSS        pBSSNode
74 )
75 {
76         int ii;
77
78         pBSSNode->bWPA2Valid = false;
79
80         pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
81         for (ii = 0; ii < 4; ii++)
82                 pBSSNode->abyCSSPK[ii] = WLAN_11i_CSS_CCMP;
83         pBSSNode->wCSSPKCount = 1;
84         for (ii = 0; ii < 4; ii++)
85                 pBSSNode->abyAKMSSAuthType[ii] = WLAN_11i_AKMSS_802_1X;
86         pBSSNode->wAKMSSAuthCount = 1;
87         pBSSNode->sRSNCapObj.bRSNCapExist = false;
88         pBSSNode->sRSNCapObj.wRSNCap = 0;
89 }
90
91 /*+
92  *
93  * Description:
94  *    Parse RSN IE.
95  *
96  * Parameters:
97  *  In:
98  *      pBSSNode - BSS list.
99  *      pRSN - Pointer to the RSN IE.
100  *  Out:
101  *      none
102  *
103  * Return Value: none.
104  *
105  -*/
106 void
107 WPA2vParseRSN(
108         PKnownBSS        pBSSNode,
109         PWLAN_IE_RSN     pRSN
110 )
111 {
112         int                 i, j;
113         unsigned short m = 0, n = 0;
114         unsigned char *pbyOUI;
115         bool bUseGK = false;
116
117         pr_debug("WPA2_ParseRSN: [%d]\n", pRSN->len);
118
119         WPA2_ClearRSN(pBSSNode);
120
121         if (pRSN->len == 2) { // ver(2)
122                 if ((pRSN->byElementID == WLAN_EID_RSN) && (pRSN->wVersion == 1))
123                         pBSSNode->bWPA2Valid = true;
124
125                 return;
126         }
127
128         if (pRSN->len < 6) { // ver(2) + GK(4)
129                 // invalid CSS, P802.11i/D10.0, p31
130                 return;
131         }
132
133         // information element header makes sense
134         if ((pRSN->byElementID == WLAN_EID_RSN) &&
135             (pRSN->wVersion == 1)) {
136                 pr_debug("Legal 802.11i RSN\n");
137
138                 pbyOUI = &(pRSN->abyRSN[0]);
139                 if (!memcmp(pbyOUI, abyOUIWEP40, 4))
140                         pBSSNode->byCSSGK = WLAN_11i_CSS_WEP40;
141                 else if (!memcmp(pbyOUI, abyOUITKIP, 4))
142                         pBSSNode->byCSSGK = WLAN_11i_CSS_TKIP;
143                 else if (!memcmp(pbyOUI, abyOUICCMP, 4))
144                         pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
145                 else if (!memcmp(pbyOUI, abyOUIWEP104, 4))
146                         pBSSNode->byCSSGK = WLAN_11i_CSS_WEP104;
147                 else if (!memcmp(pbyOUI, abyOUIGK, 4)) {
148                         // invalid CSS, P802.11i/D10.0, p32
149                         return;
150                 } else
151                         // any vendor checks here
152                         pBSSNode->byCSSGK = WLAN_11i_CSS_UNKNOWN;
153
154                 pr_debug("802.11i CSS: %X\n", pBSSNode->byCSSGK);
155
156                 if (pRSN->len == 6) {
157                         pBSSNode->bWPA2Valid = true;
158                         return;
159                 }
160
161                 if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2)
162                         pBSSNode->wCSSPKCount = *((unsigned short *)&(pRSN->abyRSN[4]));
163                         j = 0;
164                         pbyOUI = &(pRSN->abyRSN[6]);
165
166                         for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(unsigned char)); i++) {
167                                 if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i)
168                                         if (!memcmp(pbyOUI, abyOUIGK, 4)) {
169                                                 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP;
170                                                 bUseGK = true;
171                                         } else if (!memcmp(pbyOUI, abyOUIWEP40, 4)) {
172                                                 // Invalid CSS, continue to parsing
173                                         } else if (!memcmp(pbyOUI, abyOUITKIP, 4)) {
174                                                 if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP)
175                                                         pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP;
176                                                 else
177                                                         ; // Invalid CSS, continue to parsing
178                                         } else if (!memcmp(pbyOUI, abyOUICCMP, 4)) {
179                                                 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP;
180                                         } else if (!memcmp(pbyOUI, abyOUIWEP104, 4)) {
181                                                 // Invalid CSS, continue to parsing
182                                         } else {
183                                                 // any vendor checks here
184                                                 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN;
185                                         }
186                                         pbyOUI += 4;
187                                         pr_debug("abyCSSPK[%d]: %X\n",
188                                                  j-1, pBSSNode->abyCSSPK[j-1]);
189                                 } else
190                                         break;
191                         } //for
192
193                         if (bUseGK) {
194                                 if (j != 1) {
195                                         // invalid CSS, This should be only PK CSS.
196                                         return;
197                                 }
198                                 if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) {
199                                         // invalid CSS, If CCMP is enable , PK can't be CSSGK.
200                                         return;
201                                 }
202                         }
203                         if ((pBSSNode->wCSSPKCount != 0) && (j == 0)) {
204                                 // invalid CSS, No valid PK.
205                                 return;
206                         }
207                         pBSSNode->wCSSPKCount = (unsigned short)j;
208                         pr_debug("wCSSPKCount: %d\n", pBSSNode->wCSSPKCount);
209                 }
210
211                 m = *((unsigned short *)&(pRSN->abyRSN[4]));
212
213                 if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
214                         pBSSNode->wAKMSSAuthCount = *((unsigned short *)&(pRSN->abyRSN[6+4*m]));
215                         j = 0;
216                         pbyOUI = &(pRSN->abyRSN[8+4*m]);
217                         for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(unsigned char)); i++) {
218                                 if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i)
219                                         if (!memcmp(pbyOUI, abyOUI8021X, 4))
220                                                 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X;
221                                         else if (!memcmp(pbyOUI, abyOUIPSK, 4))
222                                                 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_PSK;
223                                         else
224                                                 // any vendor checks here
225                                                 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_UNKNOWN;
226                                         pr_debug("abyAKMSSAuthType[%d]: %X\n",
227                                                  j-1,
228                                                  pBSSNode->abyAKMSSAuthType[j-1]);
229                                 } else
230                                         break;
231                         }
232                         pBSSNode->wAKMSSAuthCount = (unsigned short)j;
233                         pr_debug("wAKMSSAuthCount: %d\n",
234                                  pBSSNode->wAKMSSAuthCount);
235
236                         n = *((unsigned short *)&(pRSN->abyRSN[6+4*m]));
237                         if (pRSN->len >= 12 + 4 * m + 4 * n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
238                                 pBSSNode->sRSNCapObj.bRSNCapExist = true;
239                                 pBSSNode->sRSNCapObj.wRSNCap = *((unsigned short *)&(pRSN->abyRSN[8+4*m+4*n]));
240                         }
241                 }
242                 //ignore PMKID lists bcs only (Re)Assocrequest has this field
243                 pBSSNode->bWPA2Valid = true;
244         }
245 }
246
247 /*+
248  *
249  * Description:
250  *    Set WPA IEs
251  *
252  * Parameters:
253  *  In:
254  *      pMgmtHandle - Pointer to management object
255  *  Out:
256  *      pRSNIEs     - Pointer to the RSN IE to set.
257  *
258  * Return Value: length of IEs.
259  *
260  -*/
261 unsigned int
262 WPA2uSetIEs(
263         void *pMgmtHandle,
264         PWLAN_IE_RSN pRSNIEs
265 )
266 {
267         PSMgmtObject    pMgmt = (PSMgmtObject) pMgmtHandle;
268         unsigned char *pbyBuffer = NULL;
269         unsigned int ii = 0;
270         unsigned short *pwPMKID = NULL;
271
272         if (pRSNIEs == NULL)
273                 return 0;
274
275         if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
276              (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
277             (pMgmt->pCurrBSS != NULL)) {
278                 /* WPA2 IE */
279                 pbyBuffer = (unsigned char *)pRSNIEs;
280                 pRSNIEs->byElementID = WLAN_EID_RSN;
281                 pRSNIEs->len = 6; //Version(2)+GK(4)
282                 pRSNIEs->wVersion = 1;
283                 //Group Key Cipher Suite
284                 pRSNIEs->abyRSN[0] = 0x00;
285                 pRSNIEs->abyRSN[1] = 0x0F;
286                 pRSNIEs->abyRSN[2] = 0xAC;
287                 if (pMgmt->byCSSGK == KEY_CTL_WEP)
288                         pRSNIEs->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
289                 else if (pMgmt->byCSSGK == KEY_CTL_TKIP)
290                         pRSNIEs->abyRSN[3] = WLAN_11i_CSS_TKIP;
291                 else if (pMgmt->byCSSGK == KEY_CTL_CCMP)
292                         pRSNIEs->abyRSN[3] = WLAN_11i_CSS_CCMP;
293                 else
294                         pRSNIEs->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
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 &&
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                 return pRSNIEs->len + WLAN_IEHDR_LEN;
357         }
358         return 0;
359 }