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 37/*--------------------- Static Definitions -------------------------*/ 38static int msglevel =MSG_LEVEL_INFO; 39//static int msglevel =MSG_LEVEL_DEBUG; 40/*--------------------- Static Classes ----------------------------*/ 41 42/*--------------------- Static Variables --------------------------*/ 43 44const BYTE abyOUIGK[4] = { 0x00, 0x0F, 0xAC, 0x00 }; 45const BYTE abyOUIWEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 }; 46const BYTE abyOUIWEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 }; 47const BYTE abyOUITKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 }; 48const BYTE abyOUICCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 }; 49 50const BYTE abyOUI8021X[4] = { 0x00, 0x0F, 0xAC, 0x01 }; 51const BYTE abyOUIPSK[4] = { 0x00, 0x0F, 0xAC, 0x02 }; 52 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-*/ 74void 75WPA2_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-*/ 109void 110WPA2vParseRSN ( 111 PKnownBSS pBSSNode, 112 PWLAN_IE_RSN pRSN 113 ) 114{ 115 int i, j; 116 WORD m = 0, n = 0; 117 PBYTE 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 140 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Legal 802.11i RSN\n"); 141 142 pbyOUI = &(pRSN->abyRSN[0]); 143 if ( !memcmp(pbyOUI, abyOUIWEP40, 4)) 144 pBSSNode->byCSSGK = WLAN_11i_CSS_WEP40; 145 else if ( !memcmp(pbyOUI, abyOUITKIP, 4)) 146 pBSSNode->byCSSGK = WLAN_11i_CSS_TKIP; 147 else if ( !memcmp(pbyOUI, abyOUICCMP, 4)) 148 pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP; 149 else if ( !memcmp(pbyOUI, abyOUIWEP104, 4)) 150 pBSSNode->byCSSGK = WLAN_11i_CSS_WEP104; 151 else if ( !memcmp(pbyOUI, abyOUIGK, 4)) { 152 // invalid CSS, P802.11i/D10.0, p32 153 return; 154 } else 155 // any vendor checks here 156 pBSSNode->byCSSGK = WLAN_11i_CSS_UNKNOWN; 157 158 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"802.11i CSS: %X\n", pBSSNode->byCSSGK); 159 160 if (pRSN->len == 6) { 161 pBSSNode->bWPA2Valid = TRUE; 162 return; 163 } 164 165 if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2) 166 pBSSNode->wCSSPKCount = *((PWORD) &(pRSN->abyRSN[4])); 167 j = 0; 168 pbyOUI = &(pRSN->abyRSN[6]); 169 170 for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(BYTE)); i++) { 171 172 if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i) 173 if ( !memcmp(pbyOUI, abyOUIGK, 4)) { 174 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP; 175 bUseGK = TRUE; 176 } else if ( !memcmp(pbyOUI, abyOUIWEP40, 4)) { 177 // Invialid CSS, continue to parsing 178 } else if ( !memcmp(pbyOUI, abyOUITKIP, 4)) { 179 if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP) 180 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP; 181 else 182 ; // Invialid CSS, continue to parsing 183 } else if ( !memcmp(pbyOUI, abyOUICCMP, 4)) { 184 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP; 185 } else if ( !memcmp(pbyOUI, abyOUIWEP104, 4)) { 186 // Invialid CSS, continue to parsing 187 } else { 188 // any vendor checks here 189 pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN; 190 } 191 pbyOUI += 4; 192 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyCSSPK[%d]: %X\n", j-1, pBSSNode->abyCSSPK[j-1]); 193 } else 194 break; 195 } //for 196 197 if (bUseGK == TRUE) { 198 if (j != 1) { 199 // invalid CSS, This should be only PK CSS. 200 return; 201 } 202 if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) { 203 // invalid CSS, If CCMP is enable , PK can't be CSSGK. 204 return; 205 } 206 } 207 if ((pBSSNode->wCSSPKCount != 0) && (j == 0)) { 208 // invalid CSS, No valid PK. 209 return; 210 } 211 pBSSNode->wCSSPKCount = (WORD)j; 212 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wCSSPKCount: %d\n", pBSSNode->wCSSPKCount); 213 } 214 215 m = *((PWORD) &(pRSN->abyRSN[4])); 216 217 if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2) 218 pBSSNode->wAKMSSAuthCount = *((PWORD) &(pRSN->abyRSN[6+4*m])); 219 j = 0; 220 pbyOUI = &(pRSN->abyRSN[8+4*m]); 221 for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(BYTE)); i++) { 222 if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i) 223 if ( !memcmp(pbyOUI, abyOUI8021X, 4)) 224 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X; 225 else if ( !memcmp(pbyOUI, abyOUIPSK, 4)) 226 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_PSK; 227 else 228 // any vendor checks here 229 pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_UNKNOWN; 230 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyAKMSSAuthType[%d]: %X\n", j-1, pBSSNode->abyAKMSSAuthType[j-1]); 231 } else 232 break; 233 } 234 pBSSNode->wAKMSSAuthCount = (WORD)j; 235 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount); 236 237 n = *((PWORD) &(pRSN->abyRSN[6+4*m])); 238 if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2) 239 pBSSNode->sRSNCapObj.bRSNCapExist = TRUE; 240 pBSSNode->sRSNCapObj.wRSNCap = *((PWORD) &(pRSN->abyRSN[8+4*m+4*n])); 241 } 242 } 243 //ignore PMKID lists bcs only (Re)Assocrequest has this field 244 pBSSNode->bWPA2Valid = TRUE; 245 } 246} 247 248 249/*+ 250 * 251 * Description: 252 * Set WPA IEs 253 * 254 * Parameters: 255 * In: 256 * pMgmtHandle - Pointer to management object 257 * Out: 258 * pRSNIEs - Pointer to the RSN IE to set. 259 * 260 * Return Value: length of IEs. 261 * 262-*/ 263unsigned int 264WPA2uSetIEs(void *pMgmtHandle, 265 PWLAN_IE_RSN pRSNIEs 266 ) 267{ 268 PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle; 269 PBYTE pbyBuffer = NULL; 270 unsigned int ii = 0; 271 PWORD pwPMKID = NULL; 272 273 if (pRSNIEs == NULL) { 274 return(0); 275 } 276 if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || 277 (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) && 278 (pMgmt->pCurrBSS != NULL)) { 279 /* WPA2 IE */ 280 pbyBuffer = (PBYTE) pRSNIEs; 281 pRSNIEs->byElementID = WLAN_EID_RSN; 282 pRSNIEs->len = 6; //Version(2)+GK(4) 283 pRSNIEs->wVersion = 1; 284 //Group Key Cipher Suite 285 pRSNIEs->abyRSN[0] = 0x00; 286 pRSNIEs->abyRSN[1] = 0x0F; 287 pRSNIEs->abyRSN[2] = 0xAC; 288 if (pMgmt->byCSSGK == KEY_CTL_WEP) { 289 pRSNIEs->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK; 290 } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) { 291 pRSNIEs->abyRSN[3] = WLAN_11i_CSS_TKIP; 292 } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) { 293 pRSNIEs->abyRSN[3] = WLAN_11i_CSS_CCMP; 294 } else { 295 pRSNIEs->abyRSN[3] = WLAN_11i_CSS_UNKNOWN; 296 } 297 298 // Pairwise Key Cipher Suite 299 pRSNIEs->abyRSN[4] = 1; 300 pRSNIEs->abyRSN[5] = 0; 301 pRSNIEs->abyRSN[6] = 0x00; 302 pRSNIEs->abyRSN[7] = 0x0F; 303 pRSNIEs->abyRSN[8] = 0xAC; 304 if (pMgmt->byCSSPK == KEY_CTL_TKIP) { 305 pRSNIEs->abyRSN[9] = WLAN_11i_CSS_TKIP; 306 } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) { 307 pRSNIEs->abyRSN[9] = WLAN_11i_CSS_CCMP; 308 } else if (pMgmt->byCSSPK == KEY_CTL_NONE) { 309 pRSNIEs->abyRSN[9] = WLAN_11i_CSS_USE_GROUP; 310 } else { 311 pRSNIEs->abyRSN[9] = WLAN_11i_CSS_UNKNOWN; 312 } 313 pRSNIEs->len += 6; 314 315 // Auth Key Management Suite 316 pRSNIEs->abyRSN[10] = 1; 317 pRSNIEs->abyRSN[11] = 0; 318 pRSNIEs->abyRSN[12] = 0x00; 319 pRSNIEs->abyRSN[13] = 0x0F; 320 pRSNIEs->abyRSN[14] = 0xAC; 321 if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) { 322 pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_PSK; 323 } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) { 324 pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_802_1X; 325 } else { 326 pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN; 327 } 328 pRSNIEs->len +=6; 329 330 // RSN Capabilites 331 if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == TRUE) { 332 memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2); 333 } else { 334 pRSNIEs->abyRSN[16] = 0; 335 pRSNIEs->abyRSN[17] = 0; 336 } 337 pRSNIEs->len +=2; 338 339 if ((pMgmt->gsPMKIDCache.BSSIDInfoCount > 0) && 340 (pMgmt->bRoaming == TRUE) && 341 (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) { 342 /* RSN PMKID, pointer to PMKID count */ 343 pwPMKID = (PWORD)(&pRSNIEs->abyRSN[18]); 344 *pwPMKID = 0; /* Initialize PMKID count */ 345 pbyBuffer = &pRSNIEs->abyRSN[20]; /* Point to PMKID list */ 346 for (ii = 0; ii < pMgmt->gsPMKIDCache.BSSIDInfoCount; ii++) { 347 if (!memcmp(&pMgmt-> 348 gsPMKIDCache.BSSIDInfo[ii].abyBSSID[0], 349 pMgmt->abyCurrBSSID, 350 ETH_ALEN)) { 351 (*pwPMKID)++; 352 memcpy(pbyBuffer, 353 pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyPMKID, 354 16); 355 pbyBuffer += 16; 356 } 357 } 358 if (*pwPMKID != 0) { 359 pRSNIEs->len += (2 + (*pwPMKID)*16); 360 } else { 361 pbyBuffer = &pRSNIEs->abyRSN[18]; 362 } 363 } 364 return(pRSNIEs->len + WLAN_IEHDR_LEN); 365 } 366 return(0); 367} 368