| /** @file keyMgmtApStaCommon.c |
| * |
| * @brief This file defines common api for authenticator and supplicant. |
| * |
| * Copyright (C) 2014, Marvell International Ltd. |
| * |
| * This software file (the "File") is distributed by Marvell International |
| * Ltd. under the terms of the GNU General Public License Version 2, June 1991 |
| * (the "License"). You may use, redistribute and/or modify this File in |
| * accordance with the terms and conditions of the License, a copy of which |
| * is available by writing to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the |
| * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. |
| * |
| * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE |
| * ARE EXPRESSLY DISCLAIMED. The License provides additional details about |
| * this warranty disclaimer. |
| */ |
| |
| /****************************************************** |
| Change log: |
| 03/07/2014: Initial version |
| ******************************************************/ |
| //Authenticator related function definitions |
| #include "wltypes.h" |
| #include "IEEE_types.h" |
| |
| #include "hostsa_ext_def.h" |
| #include "authenticator.h" |
| |
| #include "keyMgmtAp_rom.h" |
| #include "crypt_new_rom.h" |
| #include "keyCommonDef.h" |
| #include "pmkCache_rom.h" |
| #include "crypt_new_rom.h" |
| #include "rc4_rom.h" |
| #include "aes_cmac_rom.h" |
| #include "sha1.h" |
| #include "md5.h" |
| #include "mrvl_sha256_crypto.h" |
| |
| const UINT8 wpa_oui_none[4] = { 0x00, 0x50, 0xf2, 0x00 }; |
| const UINT8 wpa_oui01[4] = { 0x00, 0x50, 0xf2, 0x01 }; |
| const UINT8 wpa_oui02[4] = { 0x00, 0x50, 0xf2, 0x02 }; |
| const UINT8 wpa_oui03[4] = { 0x00, 0x50, 0xf2, 0x03 }; |
| const UINT8 wpa_oui04[4] = { 0x00, 0x50, 0xf2, 0x04 }; |
| const UINT8 wpa_oui05[4] = { 0x00, 0x50, 0xf2, 0x05 }; |
| const UINT8 wpa_oui06[4] = { 0x00, 0x50, 0xf2, 0x06 }; |
| |
| const UINT8 wpa2_oui01[4] = { 0x00, 0x0f, 0xac, 0x01 }; |
| const UINT8 wpa2_oui02[4] = { 0x00, 0x0f, 0xac, 0x02 }; |
| const UINT8 wpa2_oui03[4] = { 0x00, 0x0f, 0xac, 0x03 }; |
| const UINT8 wpa2_oui04[4] = { 0x00, 0x0f, 0xac, 0x04 }; |
| const UINT8 wpa2_oui05[4] = { 0x00, 0x0f, 0xac, 0x05 }; |
| const UINT8 wpa2_oui06[4] = { 0x00, 0x0f, 0xac, 0x06 }; |
| |
| const UINT8 wpa_oui[3] = { 0x00, 0x50, 0xf2 }; |
| const UINT8 kde_oui[3] = { 0x00, 0x0f, 0xac }; |
| |
| /** |
| * @brief strlen |
| * |
| * @param str A pointer to string |
| * |
| * @return Length of string |
| */ |
| t_u32 |
| wlan_strlen(const char *str) |
| { |
| t_u32 i; |
| |
| for (i = 0; str[i] != 0; i++) { |
| } |
| return i; |
| } |
| |
| static t_u32 |
| srand_new(void *priv) |
| { |
| phostsa_private psapriv = (phostsa_private)priv; |
| hostsa_util_fns *util_fns = &psapriv->util_fns; |
| t_u32 sec, usec; |
| |
| ENTER(); |
| get_system_time(util_fns, &sec, &usec); |
| sec = (sec & 0xFFFF) + (sec >> 16); |
| usec = (usec & 0xFFFF) + (usec >> 16); |
| |
| LEAVE(); |
| return (usec << 16) | sec; |
| } |
| |
| static unsigned int |
| rand_new(unsigned int seed, UINT32 randvaule) |
| { |
| unsigned int next = seed; |
| unsigned int result; |
| |
| next *= (3515245 * randvaule + randvaule * next); |
| next += 12345 + randvaule * 7; |
| result = (unsigned int)(next / 65536) % 2048; |
| |
| next *= (39018768 * randvaule + randvaule * next); |
| next += 56789 + randvaule * 4; |
| result <<= 10; |
| result ^= (unsigned int)(next / 65536) % 1024; |
| |
| next *= (89042053 * randvaule + randvaule * next); |
| next += 43728 + randvaule * 9; |
| result <<= 10; |
| result ^= (unsigned int)(next / 65536) % 1024; |
| |
| return result; |
| } |
| |
| void |
| supplicantGenerateRand(hostsa_private *priv, UINT8 *dataOut, UINT32 length) |
| { |
| UINT32 i; |
| // UINT32 valueHi, valueLo; |
| |
| /* Read mac 0 timer. ** Doesn't matter which one we read. We just need |
| a good seed. */ |
| // msi_wl_GetMCUCoreTimerTxTSF(&valueHi, &valueLo); |
| // srand(valueLo); |
| for (i = 0; i < length; i++) { |
| // dataOut[i] = rand(); |
| dataOut[i] = rand_new(srand_new(priv), i + 1); |
| } |
| } |
| |
| void |
| SetEAPOLKeyDescTypeVersion(EAPOL_KeyMsg_Tx_t *pTxEapol, |
| BOOLEAN isWPA2, BOOLEAN isKDF, BOOLEAN nonTKIP) |
| { |
| if (isWPA2) { |
| /* WPA2 */ |
| pTxEapol->keyMsg.desc_type = 2; |
| } else { |
| /* WPA */ |
| pTxEapol->keyMsg.desc_type = 254; |
| } |
| |
| if (isKDF) { |
| /* 802.11r and 802.11w use SHA256-KDF and a different |
| KeyDescVer */ |
| pTxEapol->keyMsg.key_info.KeyDescriptorVersion = 3; |
| } else if (nonTKIP) { |
| /* CCMP */ |
| pTxEapol->keyMsg.key_info.KeyDescriptorVersion = 2; |
| } else { |
| /* TKIP OR WEP */ |
| pTxEapol->keyMsg.key_info.KeyDescriptorVersion = 1; |
| } |
| } |
| |
| void |
| ComputeEAPOL_MIC(phostsa_private priv, EAPOL_KeyMsg_t *pKeyMsg, |
| UINT16 data_length, |
| UINT8 *MIC_Key, UINT8 MIC_Key_length, UINT8 micKeyDescVersion) |
| { |
| int len = data_length; |
| UINT8 *pMicData; |
| |
| pMicData = (UINT8 *)pKeyMsg; |
| |
| /* Allow the caller to override the algorithm used to get by some Cisco |
| ** CCX bugs where the wrong MIC algorithm is used */ |
| if (micKeyDescVersion == 0) { |
| /* Algorithm not specified, use proper one from key_info */ |
| micKeyDescVersion = pKeyMsg->key_info.KeyDescriptorVersion; |
| } |
| |
| switch (micKeyDescVersion) { |
| case 3: |
| /* AES-128-CMAC */ |
| mrvl_aes_cmac(priv, MIC_Key, pMicData, len, |
| (UINT8 *)pKeyMsg->key_MIC); |
| break; |
| |
| case 2: |
| /* CCMP */ |
| Mrvl_hmac_sha1((t_void *)priv, &pMicData, |
| &len, |
| 1, |
| MIC_Key, |
| (int)MIC_Key_length, |
| (UINT8 *)pKeyMsg->key_MIC, EAPOL_MIC_SIZE); |
| break; |
| |
| default: |
| case 1: |
| /* TKIP or WEP */ |
| Mrvl_hmac_md5((t_void *)priv, pMicData, |
| data_length, |
| MIC_Key, |
| (int)MIC_Key_length, (UINT8 *)pKeyMsg->key_MIC); |
| break; |
| } |
| } |
| |
| /* Returns TRUE if EAPOL MIC check passes, FALSE otherwise. */ |
| BOOLEAN |
| IsEAPOL_MICValid(phostsa_private priv, EAPOL_KeyMsg_t *pKeyMsg, UINT8 *pMICKey) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| UINT8 msgMIC[EAPOL_MIC_SIZE]; |
| |
| /* pull the MIC */ |
| memcpy(util_fns, (UINT8 *)msgMIC, (UINT8 *)pKeyMsg->key_MIC, |
| EAPOL_MIC_SIZE); |
| |
| /* zero the MIC key field before calculating the data */ |
| memset(util_fns, (UINT8 *)pKeyMsg->key_MIC, 0x00, EAPOL_MIC_SIZE); |
| |
| ComputeEAPOL_MIC(priv, pKeyMsg, (ntohs(pKeyMsg->hdr_8021x.pckt_body_len) |
| + sizeof(pKeyMsg->hdr_8021x)), |
| pMICKey, EAPOL_MIC_KEY_SIZE, 0); |
| |
| if (memcmp(util_fns, (UINT8 *)pKeyMsg->key_MIC, msgMIC, EAPOL_MIC_SIZE)) { |
| #ifdef KEYMSG_DEBUG |
| hostEventPrintf(assocAgent_getConnPtr(), |
| "EAPOL MIC Failure: cmac(%d), sha1(%d), md5(%d)", |
| (pKeyMsg->key_info.KeyDescriptorVersion == 3), |
| (pKeyMsg->key_info.KeyDescriptorVersion == 2), |
| (pKeyMsg->key_info.KeyDescriptorVersion == 1)); |
| #endif |
| /* MIC Failure */ |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| void |
| supplicantConstructContext(phostsa_private priv, UINT8 *pAddr1, |
| UINT8 *pAddr2, |
| UINT8 *pNonce1, UINT8 *pNonce2, UINT8 *pContext) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| if (memcmp(util_fns, pAddr1, pAddr2, 6) < 0) { |
| memcpy(util_fns, pContext, pAddr1, sizeof(IEEEtypes_MacAddr_t)); |
| memcpy(util_fns, (pContext + 6), pAddr2, |
| sizeof(IEEEtypes_MacAddr_t)); |
| } else { |
| memcpy(util_fns, pContext, pAddr2, sizeof(IEEEtypes_MacAddr_t)); |
| memcpy(util_fns, (pContext + 6), pAddr1, |
| sizeof(IEEEtypes_MacAddr_t)); |
| } |
| |
| if (memcmp(util_fns, pNonce1, pNonce2, NONCE_SIZE) < 0) { |
| memcpy(util_fns, pContext + 6 + 6, pNonce1, NONCE_SIZE); |
| memcpy(util_fns, pContext + 6 + 6 + NONCE_SIZE, pNonce2, |
| NONCE_SIZE); |
| } else { |
| memcpy(util_fns, pContext + 6 + 6, pNonce2, NONCE_SIZE); |
| memcpy(util_fns, pContext + 6 + 6 + NONCE_SIZE, pNonce1, |
| NONCE_SIZE); |
| } |
| } |
| |
| UINT16 |
| KeyMgmtSta_PopulateEAPOLLengthMic(phostsa_private priv, |
| EAPOL_KeyMsg_Tx_t *pTxEapol, |
| UINT8 *pEAPOLMICKey, |
| UINT8 eapolProtocolVersion, |
| UINT8 forceKeyDescVersion) |
| { |
| UINT16 frameLen; |
| |
| #if 0 // !defined(REMOVE_PATCH_HOOKS) |
| if (KeyMgmtSta_PopulateEAPOLLengthMic_hook(pTxEapol, |
| pEAPOLMICKey, |
| eapolProtocolVersion, |
| forceKeyDescVersion, |
| &frameLen)) { |
| return frameLen; |
| } |
| #endif |
| |
| if (!pTxEapol) { |
| return 0; |
| } |
| |
| frameLen = sizeof(pTxEapol->keyMsg); |
| frameLen -= sizeof(pTxEapol->keyMsg.hdr_8021x); |
| frameLen -= sizeof(pTxEapol->keyMsg.key_data); |
| frameLen += pTxEapol->keyMsg.key_material_len; |
| |
| pTxEapol->keyMsg.hdr_8021x.protocol_ver = eapolProtocolVersion; |
| pTxEapol->keyMsg.hdr_8021x.pckt_type = IEEE_8021X_PACKET_TYPE_EAPOL_KEY; |
| pTxEapol->keyMsg.hdr_8021x.pckt_body_len = htons(frameLen); |
| |
| pTxEapol->keyMsg.key_material_len |
| = htons(pTxEapol->keyMsg.key_material_len); |
| |
| ComputeEAPOL_MIC(priv, &pTxEapol->keyMsg, |
| frameLen + sizeof(pTxEapol->keyMsg.hdr_8021x), |
| pEAPOLMICKey, EAPOL_MIC_KEY_SIZE, forceKeyDescVersion); |
| |
| return frameLen; |
| } |
| |
| /* |
| ** This function generates the Pairwise transient key |
| */ |
| void |
| KeyMgmt_DerivePTK(phostsa_private priv, UINT8 *pAddr1, |
| UINT8 *pAddr2, |
| UINT8 *pNonce1, |
| UINT8 *pNonce2, UINT8 *pPTK, UINT8 *pPMK, BOOLEAN use_kdf) |
| { |
| UINT8 *pContext; |
| char *prefix; |
| |
| /* pPTK is expected to be an encryption pool buffer (at least 500 |
| bytes). ** ** Use the first portion for the ptk output. Use memory |
| in the end of ** the buffer for the context construction (76 bytes). |
| ** ** The sha256 routine assumes available memory after the context |
| for its ** own sha256 output. Space after the context (76 bytes) is |
| required ** for 2 digests (2 * 32). pContext must have at least 76 + |
| 64 bytes ** available. */ |
| pContext = pPTK + 200; |
| |
| supplicantConstructContext(priv, pAddr1, pAddr2, pNonce1, pNonce2, |
| pContext); |
| |
| prefix = "Pairwise key expansion"; |
| |
| if (use_kdf) { |
| mrvl_sha256_crypto_kdf((t_void *)priv, pPMK, PMK_LEN_MAX, prefix, 22, /* strlen(prefix) |
| */ |
| pContext, 76, /* sizeof constructed |
| context */ |
| pPTK, 384); |
| } else { |
| Mrvl_PRF((void *)priv, pPMK, PMK_LEN_MAX, (UINT8 *)prefix, 22, /* strlen(prefix) |
| */ |
| pContext, 76, /* sizeof constructed context */ |
| pPTK, 64); |
| } |
| } |
| |
| void |
| KeyMgmtSta_DeriveKeys(hostsa_private *priv, UINT8 *pPMK, |
| UINT8 *da, |
| UINT8 *sa, |
| UINT8 *ANonce, |
| UINT8 *SNonce, |
| UINT8 *EAPOL_MIC_Key, |
| UINT8 *EAPOL_Encr_Key, |
| KeyData_t *newPWKey, BOOLEAN use_kdf) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| // phostsa_private psapriv = (phostsa_private) priv; |
| // hostsa_util_fns *util_fns = &psapriv->util_fns; |
| // BufferDesc_t* pBufDesc = NULL; |
| UINT8 buf[500] = { 0 }; |
| TkipPtk_t *pPtk; |
| |
| #if 0 |
| #if !defined(REMOVE_PATCH_HOOKS) |
| if (KeyMgmtSta_DeriveKeys_hook(pPMK, |
| da, |
| sa, |
| ANonce, |
| SNonce, |
| EAPOL_MIC_Key, |
| EAPOL_Encr_Key, newPWKey, use_kdf)) { |
| return; |
| } |
| #endif |
| #endif |
| if (!pPMK || !EAPOL_MIC_Key || !newPWKey) { |
| return; |
| } |
| #if 0 |
| /* Wait forever ensures a buffer */ |
| pBufDesc = (BufferDesc_t *) bml_AllocBuffer(ramHook_encrPoolConfig, |
| 500, BML_WAIT_FOREVER); |
| pPtk = (TkipPtk_t *)BML_DATA_PTR(pBufDesc); |
| #endif |
| pPtk = (TkipPtk_t *)buf; |
| |
| KeyMgmt_DerivePTK(priv, sa, da, ANonce, SNonce, (UINT8 *)pPtk, pPMK, |
| use_kdf); |
| |
| memcpy(util_fns, EAPOL_MIC_Key, pPtk->kck, sizeof(pPtk->kck)); |
| memcpy(util_fns, EAPOL_Encr_Key, pPtk->kek, sizeof(pPtk->kek)); |
| memcpy(util_fns, newPWKey->Key, pPtk->tk, sizeof(pPtk->tk)); |
| |
| memcpy(util_fns, newPWKey->RxMICKey, |
| pPtk->rxMicKey, sizeof(pPtk->rxMicKey)); |
| |
| memcpy(util_fns, newPWKey->TxMICKey, |
| pPtk->txMicKey, sizeof(pPtk->txMicKey)); |
| |
| // bml_FreeBuffer((UINT32)pBufDesc); |
| } |
| |
| void |
| UpdateEAPOLWcbLenAndTransmit(hostsa_private *priv, pmlan_buffer pmbuf, |
| UINT16 frameLen) |
| { |
| hostsa_mlan_fns *pm_fns = &priv->mlan_fns; |
| |
| pm_fns->hostsa_tx_packet(priv->pmlan_private, pmbuf, frameLen); |
| } |
| |
| void |
| formEAPOLEthHdr(phostsa_private priv, EAPOL_KeyMsg_Tx_t *pTxEapol, |
| t_u8 *da, t_u8 *sa) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| memcpy(util_fns, (void *)pTxEapol->ethHdr.da, da, |
| IEEEtypes_ADDRESS_SIZE); |
| memcpy(util_fns, (void *)pTxEapol->ethHdr.sa, sa, |
| IEEEtypes_ADDRESS_SIZE); |
| pTxEapol->ethHdr.type = 0x8E88; |
| } |
| |
| void |
| supplicantParseWpaIe(phostsa_private priv, IEEEtypes_WPAElement_t *pIe, |
| SecurityMode_t *pWpaType, |
| Cipher_t *pMcstCipher, |
| Cipher_t *pUcstCipher, |
| AkmSuite_t *pAkmList, UINT8 akmOutMax) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| IEEEtypes_WPAElement_t *pTemp = pIe; |
| int count; |
| int akmCount = akmOutMax; |
| AkmSuite_t *pAkm = pAkmList; |
| |
| memset(util_fns, pMcstCipher, 0x00, sizeof(Cipher_t)); |
| memset(util_fns, pUcstCipher, 0x00, sizeof(Cipher_t)); |
| memset(util_fns, pAkmList, 0x00, akmOutMax * sizeof(AkmSuite_t)); |
| memset(util_fns, pWpaType, 0x00, sizeof(SecurityMode_t)); |
| |
| pWpaType->wpa = 1; |
| |
| /* record the AP's multicast cipher */ |
| if (!memcmp |
| (util_fns, (char *)pTemp->GrpKeyCipher, wpa_oui02, |
| sizeof(wpa_oui02))) { |
| /* WPA TKIP */ |
| pMcstCipher->tkip = 1; |
| } else if (!memcmp |
| (util_fns, (char *)pTemp->GrpKeyCipher, wpa_oui04, |
| sizeof(wpa_oui04))) { |
| /* WPA AES */ |
| pMcstCipher->ccmp = 1; |
| } else if (!memcmp |
| (util_fns, (char *)pTemp->GrpKeyCipher, wpa_oui01, |
| sizeof(wpa_oui01))) { |
| /* WPA WEP 40 */ |
| pMcstCipher->wep40 = 1; |
| } else if (!memcmp |
| (util_fns, (char *)pTemp->GrpKeyCipher, wpa_oui05, |
| sizeof(wpa_oui05))) { |
| /* WPA WEP 104 */ |
| pMcstCipher->wep104 = 1; |
| } |
| |
| count = pTemp->PwsKeyCnt; |
| |
| while (count) { |
| /* record the AP's unicast cipher */ |
| if (!memcmp(util_fns, (char *)pTemp->PwsKeyCipherList, |
| wpa_oui02, sizeof(wpa_oui02))) { |
| /* WPA TKIP */ |
| pUcstCipher->tkip = 1; |
| } else if (!memcmp(util_fns, (char *)pTemp->PwsKeyCipherList, |
| wpa_oui04, sizeof(wpa_oui04))) { |
| /* WPA AES */ |
| pUcstCipher->ccmp = 1; |
| } |
| count--; |
| |
| if (count) { |
| pTemp = (IEEEtypes_WPAElement_t *)((UINT8 *)pTemp + |
| sizeof(pTemp-> |
| PwsKeyCipherList)); |
| } |
| } |
| |
| count = pTemp->AuthKeyCnt; |
| |
| while (count) { |
| if (akmCount) { |
| /* Store the AKM */ |
| memcpy(util_fns, pAkm, |
| (char *)pTemp->AuthKeyList, |
| sizeof(pTemp->AuthKeyList)); |
| pAkm++; |
| akmCount--; |
| } |
| |
| count--; |
| |
| if (count) { |
| pTemp = (IEEEtypes_WPAElement_t *)((UINT8 *)pTemp |
| + |
| sizeof(pTemp-> |
| AuthKeyList)); |
| } |
| } |
| |
| if (!memcmp(util_fns, pAkmList, wpa_oui_none, sizeof(wpa_oui_none))) { |
| pWpaType->wpaNone = 1; |
| } |
| } |
| |
| void |
| supplicantParseMcstCipher(phostsa_private priv, Cipher_t *pMcstCipherOut, |
| UINT8 *pGrpKeyCipher) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| memset(util_fns, pMcstCipherOut, 0x00, sizeof(Cipher_t)); |
| |
| /* record the AP's multicast cipher */ |
| if (!memcmp(util_fns, pGrpKeyCipher, wpa2_oui02, sizeof(wpa2_oui02))) { |
| /* WPA2 TKIP */ |
| pMcstCipherOut->tkip = 1; |
| } else if (!memcmp |
| (util_fns, pGrpKeyCipher, wpa2_oui04, sizeof(wpa2_oui04))) { |
| /* WPA2 AES */ |
| pMcstCipherOut->ccmp = 1; |
| } else if (!memcmp |
| (util_fns, pGrpKeyCipher, wpa2_oui01, sizeof(wpa2_oui01))) { |
| /* WPA2 WEP 40 */ |
| pMcstCipherOut->wep40 = 1; |
| } else if (!memcmp |
| (util_fns, pGrpKeyCipher, wpa2_oui05, sizeof(wpa2_oui05))) { |
| /* WPA2 WEP 104 */ |
| pMcstCipherOut->wep104 = 1; |
| } |
| } |
| |
| void |
| supplicantParseUcstCipher(phostsa_private priv, Cipher_t *pUcstCipherOut, |
| UINT8 pwsKeyCnt, UINT8 *pPwsKeyCipherList) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| UINT8 count; |
| |
| memset(util_fns, pUcstCipherOut, 0x00, sizeof(Cipher_t)); |
| |
| /* Cycle through the PwsKeyCipherList and record each unicast cipher */ |
| for (count = 0; count < pwsKeyCnt; count++) { |
| /* record the AP's unicast cipher */ |
| if (!memcmp(util_fns, pPwsKeyCipherList + (count * 4), |
| wpa2_oui02, sizeof(wpa2_oui02))) { |
| /* WPA2 TKIP */ |
| pUcstCipherOut->tkip = 1; |
| } else if (!memcmp(util_fns, pPwsKeyCipherList + (count * 4), |
| wpa2_oui04, sizeof(wpa2_oui04))) { |
| /* WPA2 AES */ |
| pUcstCipherOut->ccmp = 1; |
| } |
| } |
| } |
| |
| void |
| supplicantParseRsnIe(phostsa_private priv, IEEEtypes_RSNElement_t *pRsnIe, |
| SecurityMode_t *pWpaTypeOut, |
| Cipher_t *pMcstCipherOut, |
| Cipher_t *pUcstCipherOut, |
| AkmSuite_t *pAkmListOut, |
| UINT8 akmOutMax, |
| IEEEtypes_RSNCapability_t *pRsnCapOut, |
| Cipher_t *pGrpMgmtCipherOut) |
| { |
| hostsa_util_fns *util_fns = &priv->util_fns; |
| UINT8 *pIeData; |
| UINT8 *pIeEnd; |
| UINT8 *pGrpKeyCipher; |
| UINT16 pwsKeyCnt; |
| UINT8 *pPwsKeyCipherList; |
| UINT16 authKeyCnt; |
| UINT8 *pAuthKeyList; |
| |
| IEEEtypes_RSNCapability_t *pRsnCap; |
| |
| UINT16 *pPMKIDCnt; |
| |
| UINT8 *pGrpMgmtCipher; |
| #if 0 |
| #if !defined(REMOVE_PATCH_HOOKS) |
| if (supplicantParseRsnIe_hook(pRsnIe, |
| pWpaTypeOut, |
| pMcstCipherOut, |
| pUcstCipherOut, |
| pAkmListOut, |
| akmOutMax, |
| pRsnCapOut, pGrpMgmtCipherOut)) { |
| return; |
| } |
| #endif |
| #endif |
| memset(util_fns, pWpaTypeOut, 0x00, sizeof(SecurityMode_t)); |
| |
| pWpaTypeOut->wpa2 = 1; |
| |
| /* Set the start and end of the IE data */ |
| pIeData = (UINT8 *)&pRsnIe->Ver; |
| pIeEnd = pIeData + pRsnIe->Len; |
| |
| /* Skip past the version field */ |
| pIeData += sizeof(pRsnIe->Ver); |
| |
| /* Parse the group key cipher list */ |
| pGrpKeyCipher = pIeData; |
| pIeData += sizeof(pRsnIe->GrpKeyCipher); |
| supplicantParseMcstCipher(priv, pMcstCipherOut, pGrpKeyCipher); |
| |
| /* Parse the pairwise key cipher list */ |
| memcpy(util_fns, &pwsKeyCnt, pIeData, sizeof(pwsKeyCnt)); |
| pIeData += sizeof(pRsnIe->PwsKeyCnt); |
| |
| pPwsKeyCipherList = pIeData; |
| pIeData += pwsKeyCnt * sizeof(pRsnIe->PwsKeyCipherList); |
| supplicantParseUcstCipher(priv, pUcstCipherOut, pwsKeyCnt, |
| pPwsKeyCipherList); |
| |
| /* Parse and return the AKM list */ |
| memcpy(util_fns, &authKeyCnt, pIeData, sizeof(authKeyCnt)); |
| pIeData += sizeof(pRsnIe->AuthKeyCnt); |
| |
| pAuthKeyList = pIeData; |
| pIeData += authKeyCnt * sizeof(pRsnIe->AuthKeyList); |
| memset(util_fns, pAkmListOut, 0x00, akmOutMax * sizeof(AkmSuite_t)); |
| memcpy(util_fns, pAkmListOut, |
| pAuthKeyList, |
| MIN(authKeyCnt, akmOutMax) * sizeof(pRsnIe->AuthKeyList)); |
| |
| DBG_HEXDUMP(MCMD_D, " pAuthKeyList", |
| (t_u8 *)pAuthKeyList, MIN(authKeyCnt, |
| akmOutMax) * |
| sizeof(pRsnIe->AuthKeyList)); |
| DBG_HEXDUMP(MCMD_D, " pAuthKeyList", (t_u8 *)pAkmListOut, |
| MIN(authKeyCnt, akmOutMax) * sizeof(pRsnIe->AuthKeyList)); |
| /* Check if the RSN Capability is included */ |
| if (pIeData < pIeEnd) { |
| pRsnCap = (IEEEtypes_RSNCapability_t *)pIeData; |
| pIeData += sizeof(pRsnIe->RsnCap); |
| |
| if (pRsnCapOut) { |
| memcpy(util_fns, pRsnCapOut, pRsnCap, |
| sizeof(IEEEtypes_RSNCapability_t)); |
| } |
| } |
| |
| /* Check if the PMKID count is included */ |
| if (pIeData < pIeEnd) { |
| pPMKIDCnt = (UINT16 *)pIeData; |
| pIeData += sizeof(pRsnIe->PMKIDCnt); |
| |
| /* Check if the PMKID List is included */ |
| if (pIeData < pIeEnd) { |
| /* pPMKIDList = pIeData; <-- Currently not used in |
| parsing */ |
| pIeData += *pPMKIDCnt * sizeof(pRsnIe->PMKIDList); |
| } |
| } |
| |
| /* Check if the Group Mgmt Cipher is included */ |
| if (pIeData < pIeEnd) { |
| pGrpMgmtCipher = pIeData; |
| |
| if (pGrpMgmtCipherOut) { |
| memcpy(util_fns, pGrpMgmtCipherOut, |
| pGrpMgmtCipher, sizeof(pRsnIe->GrpMgmtCipher)); |
| } |
| } |
| } |