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