prima: WLAN Driver Release 3.1.7.9
This is the initial release of the Prima WLAN Driver
diff --git a/CORE/BAP/src/bapRsnSsmEapol.c b/CORE/BAP/src/bapRsnSsmEapol.c
new file mode 100644
index 0000000..6d12fdc
--- /dev/null
+++ b/CORE/BAP/src/bapRsnSsmEapol.c
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Woodside Networks, Inc proprietary. All rights reserved.
+ * File: $Header: //depot/software/projects/feature_branches/gen5_phase1/os/linux/classic/ap/apps/ssm/lib/aniSsmEapol.c#2 $
+ *
+ * Contains definitions of various utilities for EAPoL frame
+ * parsing and creation.
+ *
+ * Author: Mayank D. Upadhyay
+ * Date: 19-June-2002
+ * History:-
+ * Date Modified by Modification Information
+ * ------------------------------------------------------
+ *
+ */
+#include "vos_utils.h"
+#include <bapRsnAsfPacket.h>
+#include <bapRsnErrors.h>
+#include <bapRsnSsmEapol.h>
+#include "bapRsn8021xFsm.h"
+#include "vos_memory.h"
+
+//#include "aniSsmUtils.h"
+
+#define CHECK_RETVAL(retVal) \
+ assert(retVal == ANI_OK); \
+ if (retVal != ANI_OK) return ANI_E_FAILED;
+
+
+//TODO: Put these in an array after EAPOL_TYPE is made an enum
+#define ANI_EAPOL_TYPE_PACKET_STR "EAP"
+#define ANI_EAPOL_TYPE_START_STR "START"
+#define ANI_EAPOL_TYPE_LOGOFF_STR "LOGOFF"
+#define ANI_EAPOL_TYPE_KEY_STR "KEY"
+#define ANI_EAPOL_TYPE_ASF_ALERT_STR "ALERT"
+#define ANI_EAPOL_TYPE_UNKNOWN_STR "UNKNOWN"
+
+/**
+ * The EAPOL packet is structured as follows:
+ */
+#define DST_MAC_POS 0
+#define SRC_MAC_POS 6
+#define ETHER_PROTO_POS 12
+#define EAPOL_VERSION_POS 14
+#define ANI_EAPOL_TYPE_POS 15
+#define EAPOL_BODY_LEN_POS 16
+#define EAPOL_BODY_POS EAPOL_RX_HEADER_SIZE
+
+#define EAPOL_BODY_LEN_SIZE 2
+
+#define ANI_SSM_LEGACY_RC4_KEY_SIGN_OFFSET EAPOL_BODY_POS + 28
+
+/**
+ * Bitmasks for the RSN Key Information field
+ */
+#define ANI_SSM_RSN_KEY_DESC_VERS_MASK 0x0007
+#define ANI_SSM_RSN_UNICAST_MASK 0x0008
+#define ANI_SSM_RSN_KEY_INDEX_MASK 0x0030
+#define ANI_SSM_RSN_INSTALL_MASK 0x0040
+#define ANI_SSM_RSN_ACK_MASK 0x0080
+#define ANI_SSM_RSN_MIC_MASK 0x0100
+#define ANI_SSM_RSN_SECURE_MASK 0x0200
+#define ANI_SSM_RSN_ERROR_MASK 0x0400
+#define ANI_SSM_RSN_REQUEST_MASK 0x0800
+#define ANI_SSM_RSN_ENC_KEY_DATA_MASK 0x1000
+
+#define ANI_SSM_RSN_KEY_DESC_VERS_OFFSET 0
+#define ANI_SSM_RSN_KEY_INDEX_OFFSET 4
+
+#define ANI_SSM_RSN_KEY_MIC_OFFSET EAPOL_BODY_POS + 77
+
+/**
+ * Other hard coded values for convenience:
+ */
+static const v_U8_t
+ANI_ETH_P_EAPOL_BYTES[2] = {0x00, 0x03};//BT-AMP security type{0x88, 0x8e};
+static const v_U8_t
+EAPOL_VERSION_BYTES[1] = {EAPOL_VERSION_1};
+static const v_U8_t
+ANI_EAPOL_TYPE_PACKET_BYTES[1] = {ANI_EAPOL_TYPE_PACKET};
+static const v_U8_t
+ANI_EAPOL_TYPE_START_BYTES[1] = {ANI_EAPOL_TYPE_START};
+static const v_U8_t
+ANI_EAPOL_TYPE_LOGOFF_BYTES[1] = {ANI_EAPOL_TYPE_LOGOFF};
+static const v_U8_t
+ANI_EAPOL_TYPE_KEY_BYTES[1] = {ANI_EAPOL_TYPE_KEY};
+static const v_U8_t
+ANI_EAPOL_TYPE_ASF_ALERT_BYTES[1] = {ANI_EAPOL_TYPE_ASF_ALERT};
+static const v_U8_t
+ZERO_BYTES[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static v_U8_t BAP_RSN_LLC_HEADER[] = {0xAA, 0xAA, 0x03, 0x00, 0x19, 0x58 };
+
+
+
+static int
+parseRsnKeyDesc(tAniPacket *packet,
+ tAniEapolRsnKeyDesc **rsnDescPtr);
+
+static int
+parseRsnKeyInfo(tAniPacket *packet,
+ tAniRsnKeyInfo *info);
+
+static int
+writeRsnKeyDesc(tAniPacket *packet,
+ tAniEapolRsnKeyDesc *rsnDesc,
+ v_U8_t keyDescType);
+
+static int
+writeRsnKeyInfo(tAniPacket *packet, tAniRsnKeyInfo *info);
+
+static int
+writeRsnKeyMic(v_U32_t cryptHandle,
+ tAniPacket *eapolFrame,
+ tAniEapolRsnKeyDesc *rsnDesc,
+ v_U8_t *micKey,
+ v_U32_t micKeyLen);
+
+static int
+checkRsnKeyMic(v_U32_t cryptHandle,
+ tAniPacket *eapolFrame,
+ tAniEapolRsnKeyDesc *rsnDesc,
+ v_U8_t *micKey,
+ v_U32_t micKeyLen);
+
+extern void authEapolHandler( tAuthRsnFsm *fsm, tAniPacket *eapolFrame,
+ tAniMacAddr dstMac,
+ tAniMacAddr srcMac,
+ v_U8_t *type);
+extern void suppEapolHandler( tSuppRsnFsm *fsm, tAniPacket *eapolFrame,
+ tAniMacAddr dstMac,
+ tAniMacAddr srcMac,
+ v_U8_t *type);
+
+/**
+ * addEapolHeaders
+ *
+ * FUNCTION:
+ * Prepends the EAPOL header to a packet.
+ *
+ * ASSUMPTIONS:
+ * The packet has enough space available for prepending the EAPOL
+ * header.
+ *
+ * @param packet the packet to prepend to
+ * @param dstMac the MAC address of the destination (authenticator)
+ * @param srcMac the MAC address of the source (supplicant)
+ * @param eapolType the EAPOL-Type field
+ *
+ * @return ANI_OK if the operation succeeds
+ */
+static int
+addEapolHeaders(tAniPacket *packet,
+ tAniMacAddr dstMac,
+ tAniMacAddr srcMac,
+ v_U8_t eapolType)
+{
+ int retVal;
+ v_U16_t len;
+
+ do
+ {
+ retVal = aniAsfPacketGetLen(packet);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ len = retVal;
+ retVal = aniAsfPacketPrepend16(packet, len);
+
+ retVal = aniAsfPacketPrepend8(packet, eapolType);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketPrependBuffer(packet, EAPOL_VERSION_BYTES, 1);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketPrependBuffer(packet, ANI_ETH_P_EAPOL_BYTES, 2);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ //Since TL expects SNAP header in all packets we send, put it in
+ retVal = aniAsfPacketPrependBuffer(packet, BAP_RSN_LLC_HEADER, sizeof(BAP_RSN_LLC_HEADER));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ //packet length
+ len += 6/*length + eapolType+version + eth_type*/ + sizeof(BAP_RSN_LLC_HEADER);
+ retVal = aniAsfPacketPrepend16(packet, len);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketPrependBuffer(packet, srcMac, sizeof(tAniMacAddr));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketPrependBuffer(packet, dstMac, sizeof(tAniMacAddr));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+ }while( 0 );
+
+ return retVal;
+}
+
+/**
+ * aniEapolWriteStart
+ *
+ * FUNCTION:
+ * Writes an EAPOL-Start frame to the packet. It is only used by the
+ * supplicant.
+ *
+ * LOGIC:
+ * Prepend the appropriate EAPOL header to the packet. There is no
+ * EAPOL payload for this kind of frame.
+ *
+ * ASSUMPTIONS:
+ * The packet has enough space available for prepending the header.
+ *
+ * @param packet the packet to which the frame should be written
+ * @param dstMac the MAC address of the destination (authenticator)
+ * @param srcMac the MAC address of the source (supplicant)
+ *
+ * @return ANI_OK if the operation succeeds
+ */
+int
+aniEapolWriteStart(tAniPacket *packet,
+ tAniMacAddr dstMac,
+ tAniMacAddr srcMac)
+{
+ return ( addEapolHeaders(packet, dstMac, srcMac, ANI_EAPOL_TYPE_START) );
+}
+
+/**
+ * aniEapolWriteEapPacket
+ *
+ * FUNCTION:
+ * Writes the EAPOL/EAP-Packet frame headers. It is used
+ * by both the authenticator and the supplicant. This creates an EAPOL
+ * frame that is carrying an EAP message as its payload.
+ *
+ * LOGIC:
+ * Prepend the appropriate EAPOL header to the packet.
+ *
+ * ASSUMPTIONS:
+ * The EAP message (ie., the payload) is already available in the
+ * packet and that the packet has enough space available for
+ * prepending the EAPOL header.
+ *
+ * @param packet the packet containing the EAP message
+ * @param dstMac the MAC address of the destination (authenticator)
+ * @param srcMac the MAC address of the source (supplicant)
+ *
+ * @return ANI_OK if the operation succeeds
+ */
+int
+aniEapolWriteEapPacket(tAniPacket *eapPacket,
+ tAniMacAddr dstMac,
+ tAniMacAddr srcMac)
+{
+ return( addEapolHeaders(eapPacket, dstMac, srcMac, ANI_EAPOL_TYPE_PACKET) );
+}
+
+/**
+ * aniEapolParse
+ *
+ * FUNCTION:
+ * Parses an EAPoL frame to the first level of headers (no EAP
+ * headers are parsed).
+ *
+ * NOTE: This is a non-destructive read, that is the
+ * headers are not stripped off the packet. However, any additional
+ * data at the end of the packet, beyond what the EAPoL headers encode
+ * will be stripped off.
+ *
+ * @param packet the packet containing the EAPoL frame to parse
+ * @param dstMac a pointer to set to the location of the destination
+ * MAC address
+ * @param srcMac a pointer to set to the location of the source
+ * MAC address
+ * @param type a pointer to set to the location of the EAPOL type
+ * field.
+ *
+ * @return the non-negative length of the EAPOL payload if the operation
+ * succeeds
+ */
+int
+aniEapolParse(tAniPacket *packet,
+ v_U8_t **dstMac,
+ v_U8_t **srcMac,
+ v_U8_t **type)
+{
+ v_U16_t frameType;
+ v_U8_t *ptr;
+ int retVal;
+ int tmp;
+
+ if (aniAsfPacketGetLen(packet) < EAPOL_BODY_POS)
+ return ANI_E_ILLEGAL_ARG;
+
+ retVal = aniAsfPacketGetBytes(packet, &ptr);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) )
+ {
+ return retVal;
+ }
+
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_INFO,
+ "Supp parsing EAPOL packet of len %d: \n",
+ retVal);
+
+ frameType = (ptr[ETHER_PROTO_POS] << 8) + ptr[ETHER_PROTO_POS+1];
+
+ /*
+ * Validate the EAPOL-FRAME
+ */
+
+ if (frameType != ANI_ETH_P_EAPOL)
+ return ANI_E_ILLEGAL_ARG;
+
+ *dstMac = ptr + DST_MAC_POS;
+ *srcMac = ptr + SRC_MAC_POS;
+
+ // if (ptr[EAPOL_VERSION_POS] != EAPOL_VERSION_1)
+ // return ANI_E_ILLEGAL_ARG;
+
+ *type = ptr + ANI_EAPOL_TYPE_POS;
+ retVal = (ptr[EAPOL_BODY_LEN_POS] << 8) + ptr[EAPOL_BODY_LEN_POS + 1];
+
+ /*
+ * Validate the length of the body. Allow for longer
+ * packets than encoded, but encoding should not be larger than
+ * packet.
+ * Note: EAPOL body len does not include headers
+ */
+ tmp = aniAsfPacketGetLen(packet) - EAPOL_RX_HEADER_SIZE;
+ if (retVal > tmp)
+ {
+ retVal = ANI_E_ILLEGAL_ARG;
+ }
+ else {
+ if (retVal < tmp)
+ {
+ retVal = aniAsfPacketTruncateFromRear(packet, tmp - retVal);
+ }
+ }
+
+ return retVal;
+}
+
+/**
+ * aniEapolWriteKey
+ *
+ * Writes out a complete EAPOL-Key frame. The key descriptor is
+ * appended to the packet and the EAPOL header is prepended to it. If
+ * a micKey is passed in, then a MIC is calculated and inserted into
+ * the frame.
+ *
+ * @param packet the packet to write to
+ * @param dstMac the destination MAC address
+ * @param srcMac the source MAC address
+ * @param descType the key descriptor type
+ * (ANI_EAPOL_KEY_DESC_TYPE_LEGACY_RC4 or
+ * ANI_EAPOL_KEY_DESC_TYPE_RSN).
+ * @param keyDescData the key descriptor data corresponding to the
+ * above descType. The signature field is ignored and will be
+ * generated in the packet. The key bytes are expected to be encrypted
+ * if they need to be encrypted.
+ * @param micKey the MIC key
+ * @param micKeyLen the number of bytes in the MIC key
+ *
+ * @return ANI_OK if the operation succeeds
+ *
+ */
+int
+aniEapolWriteKey(v_U32_t cryptHandle,
+ tAniPacket *packet,
+ tAniMacAddr dstMac,
+ tAniMacAddr srcMac,
+ int descType,
+ void *keyDescData,
+ v_U8_t *micKey,
+ v_U32_t micKeyLen)
+{
+ int retVal;
+
+ if (packet == NULL)
+ return ANI_E_NULL_VALUE;
+
+ do
+ {
+ if ((descType == ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW)
+ || (descType == ANI_EAPOL_KEY_DESC_TYPE_RSN))
+ {
+
+ retVal = writeRsnKeyDesc(packet,
+ (tAniEapolRsnKeyDesc *) keyDescData,
+ // Indicate
+ // ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW
+ // or ANI_EAPOL_KEY_DESC_TYPE_RSN
+ descType);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) )
+ {
+ break;
+ }
+
+ retVal = addEapolHeaders(packet, dstMac, srcMac, ANI_EAPOL_TYPE_KEY);
+ if( !ANI_IS_STATUS_SUCCESS(retVal) ) break;
+
+ retVal = writeRsnKeyMic(cryptHandle,
+ packet,
+ (tAniEapolRsnKeyDesc *) keyDescData,
+ micKey, micKeyLen);
+ if( !ANI_IS_STATUS_SUCCESS(retVal) ) break;
+
+ }
+ else {
+ VOS_ASSERT( 0 );
+ return ANI_E_ILLEGAL_ARG;
+ }
+ }while( 0 );
+
+ return retVal;
+}
+
+
+/**
+ * aniEapolParseKey
+ *
+ * Parses and verifies a complete EAPOL-Key frame. The key descriptor
+ * type is returned and so is a newly allocated key descriptor structure
+ * that is appropriate for the type.
+ *
+ * NOTE: This is a non-destructive read. That is, the packet headers
+ * will be unchanged at the end of this read operation. This is so
+ * that a followup MIC check may be done on the complete packet. If
+ * the packet parsing fails, the packet headers are not guaranteed to
+ * be unchanged.
+ *
+ * @param packet the packet to read from. Note that the frame is not
+ * expected to contain any additional padding at the end other than
+ * the exact number of key bytes. (The aniEapolParse function will
+ * ensure this.)
+ * @param descType is set to the key descriptor type
+ * (ANI_EAPOL_KEY_DESC_TYPE_LEGACY_RC4 or
+ * ANI_EAPOL_KEY_DESC_TYPE_RSN).
+ * @param keyDescData is set to a newly allocated key descriptor
+ * corresponding to the above descType. The signature field is
+ * verified. The key bytes will be returned encrypted. It is the
+ * responsibility of the caller to free this structure and the data
+ * contained therein.
+ *
+ * @return ANI_OK if the operation succeeds
+ */
+int
+aniEapolParseKey(tAniPacket *packet,
+ int *descType,
+ void **keyDescData)
+{
+ int retVal;
+ v_U8_t *bytes;
+ v_U32_t eapolFrameLen;
+
+ if (packet == NULL)
+ return ANI_E_NULL_VALUE;
+
+ do
+ {
+ eapolFrameLen = aniAsfPacketGetLen(packet);
+
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_INFO, "Supp parsing EAPOL-Key frame of len %d\n",
+ eapolFrameLen);
+
+ retVal = aniAsfPacketTruncateFromFront(packet, EAPOL_RX_HEADER_SIZE);
+ if( !ANI_IS_STATUS_SUCCESS(retVal) ) break;
+
+ retVal = aniAsfPacketGetBytes(packet, &bytes);
+ if( !ANI_IS_STATUS_SUCCESS(retVal) ) break;
+
+ if (*bytes == ANI_EAPOL_KEY_DESC_TYPE_RSN ||
+ *bytes == ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW)
+ {
+ tAniEapolRsnKeyDesc *rsnDesc = NULL;
+
+ //*descType = ANI_EAPOL_KEY_DESC_TYPE_RSN;
+ *descType = (*bytes == ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW ?
+ ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW : ANI_EAPOL_KEY_DESC_TYPE_RSN) ;
+ retVal = parseRsnKeyDesc(packet, &rsnDesc);
+ if( !ANI_IS_STATUS_SUCCESS(retVal) ) break;
+ *keyDescData = rsnDesc;
+ }
+ else
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ "Supp received unknown EAPOL-Key descriptor: %d\n",
+ *bytes);
+ retVal = ANI_E_ILLEGAL_ARG;
+ break;
+ }
+
+ aniAsfPacketMoveLeft(packet, eapolFrameLen);
+ }while( 0 );
+
+ return retVal;
+}
+
+
+
+static int
+parseRsnKeyDesc(tAniPacket *packet,
+ tAniEapolRsnKeyDesc **rsnDescPtr)
+{
+ int retVal = ANI_OK;
+ int len;
+ v_U8_t *bytes;
+ tAniEapolRsnKeyDesc *rsnDesc = NULL;
+
+ do
+ {
+ aniAsfPacketTruncateFromFront(packet, 1); // Desc-Type
+
+ rsnDesc = (tAniEapolRsnKeyDesc *)
+ vos_mem_malloc( sizeof(tAniEapolRsnKeyDesc) );
+
+ if (rsnDesc == NULL)
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ "Supp could not malloc EAPOL-Key Descriptor for RSN\n");
+ retVal = ANI_E_MALLOC_FAILED;
+ break;
+ }
+
+ retVal = parseRsnKeyInfo(packet, &rsnDesc->info);
+ if (retVal != ANI_OK) break;
+
+ retVal = aniAsfPacketGet16(packet, &rsnDesc->keyLen);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+
+ len = sizeof(rsnDesc->replayCounter);
+ retVal = aniAsfPacketGetN(packet, len, &bytes);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+ vos_mem_copy(rsnDesc->replayCounter, bytes, len);
+
+ len = sizeof(rsnDesc->keyNonce);
+ retVal = aniAsfPacketGetN(packet, len, &bytes);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+ vos_mem_copy(rsnDesc->keyNonce, bytes, len);
+
+ len = sizeof(rsnDesc->keyIv);
+ retVal = aniAsfPacketGetN(packet, len, &bytes);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+ vos_mem_copy(rsnDesc->keyIv, bytes, len);
+
+ len = sizeof(rsnDesc->keyRecvSeqCounter);
+ retVal = aniAsfPacketGetN(packet, len, &bytes);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+ vos_mem_copy(rsnDesc->keyRecvSeqCounter, bytes, len);
+
+ len = sizeof(rsnDesc->keyId);
+ retVal = aniAsfPacketGetN(packet, len, &bytes);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+ vos_mem_copy(rsnDesc->keyId, bytes, len);
+
+ len = sizeof(rsnDesc->keyMic);
+ retVal = aniAsfPacketGetN(packet, len, &bytes);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+ vos_mem_copy(rsnDesc->keyMic, bytes, len);
+
+ retVal = aniAsfPacketGet16(packet, &rsnDesc->keyDataLen);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+
+ len = rsnDesc->keyDataLen;
+ if (len > 0) {
+ // We have a key
+ retVal = aniAsfPacketGetN(packet, len, &bytes);
+ if (retVal != ANI_OK)
+ {
+ break;
+ }
+ rsnDesc->keyData = (v_U8_t*)vos_mem_malloc(len);
+ if (rsnDesc->keyData == NULL)
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Could not allocate RSN key bytes!\n");
+ VOS_ASSERT( 0 );
+ retVal = ANI_E_MALLOC_FAILED;
+ break;
+ }
+ vos_mem_copy(rsnDesc->keyData, bytes, len);
+ }
+ else {
+ rsnDesc->keyData = NULL;
+ }
+
+ *rsnDescPtr = rsnDesc;
+
+ }while( 0 );
+
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) )
+ {
+ vos_mem_free(rsnDesc);
+ }
+
+ return retVal;
+}
+
+static int
+parseRsnKeyInfo(tAniPacket *packet,
+ tAniRsnKeyInfo *info)
+{
+ v_U16_t tmp;
+ int retVal;
+
+ retVal = aniAsfPacketGet16(packet, &tmp);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) )
+ {
+ return retVal;
+ }
+
+ info->keyDescVers = (tmp & ANI_SSM_RSN_KEY_DESC_VERS_MASK)
+ >> ANI_SSM_RSN_KEY_DESC_VERS_OFFSET;
+ if (info->keyDescVers != ANI_EAPOL_KEY_DESC_VERS_RC4 &&
+ info->keyDescVers != ANI_EAPOL_KEY_DESC_VERS_AES)
+ return ANI_E_ILLEGAL_ARG;
+
+ info->unicastFlag = (tmp & ANI_SSM_RSN_UNICAST_MASK) ?
+ eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE;
+ info->keyId = (tmp & ANI_SSM_RSN_KEY_INDEX_MASK)
+ >> ANI_SSM_RSN_KEY_INDEX_OFFSET;
+ info->installFlag = (tmp & ANI_SSM_RSN_INSTALL_MASK) ?
+ eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE;
+ info->ackFlag = (tmp & ANI_SSM_RSN_ACK_MASK) ?
+ eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE;
+ info->micFlag = (tmp & ANI_SSM_RSN_MIC_MASK) ?
+ eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE;
+ info->secureFlag = (tmp & ANI_SSM_RSN_SECURE_MASK) ?
+ eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE;
+ info->errorFlag = (tmp & ANI_SSM_RSN_ERROR_MASK) ?
+ eANI_BOOLEAN_TRUE: eANI_BOOLEAN_FALSE;
+ info->requestFlag = (tmp & ANI_SSM_RSN_REQUEST_MASK) ?
+ eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE;
+ info->encKeyDataFlag = (tmp & ANI_SSM_RSN_ENC_KEY_DATA_MASK) ?
+ eANI_BOOLEAN_TRUE : eANI_BOOLEAN_FALSE;
+
+ return ANI_OK;
+}
+
+
+static int
+writeRsnKeyDesc(tAniPacket *packet,
+ tAniEapolRsnKeyDesc *rsnDesc,
+ v_U8_t keyDescType)
+{
+ int retVal;
+
+ do
+ {
+ // This can be either ANI_EAPOL_KEY_DESC_TYPE_RSN
+ // or ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW
+ retVal = aniAsfPacketAppend8(packet, keyDescType);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = writeRsnKeyInfo(packet, &rsnDesc->info);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketAppend16(packet, rsnDesc->keyLen);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketAppendBuffer(packet,
+ rsnDesc->replayCounter,
+ sizeof(rsnDesc->replayCounter));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketAppendBuffer(packet,
+ rsnDesc->keyNonce,
+ sizeof(rsnDesc->keyNonce));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketAppendBuffer(packet,
+ rsnDesc->keyIv,
+ sizeof(rsnDesc->keyIv));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketAppendBuffer(packet,
+ rsnDesc->keyRecvSeqCounter,
+ sizeof(rsnDesc->keyRecvSeqCounter));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketAppendBuffer(packet,
+ rsnDesc->keyId,
+ sizeof(rsnDesc->keyId));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ // Zero out the key MIC
+ retVal = aniAsfPacketAppendBuffer(packet,
+ ZERO_BYTES,
+ sizeof(rsnDesc->keyMic));
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ retVal = aniAsfPacketAppend16(packet, rsnDesc->keyDataLen);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+
+ if (rsnDesc->keyDataLen != 0)
+ {
+ retVal = aniAsfPacketAppendBuffer(packet,
+ rsnDesc->keyData,
+ rsnDesc->keyDataLen);
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+ }
+ }while( 0 );
+
+ return retVal;
+}
+
+static int
+writeRsnKeyInfo(tAniPacket *packet, tAniRsnKeyInfo *info)
+{
+ int retVal;
+ v_U16_t tmp;
+ v_U16_t infoValue;
+
+ infoValue = 0;
+
+ tmp = (v_U16_t)info->keyDescVers;
+ tmp = tmp << ANI_SSM_RSN_KEY_DESC_VERS_OFFSET;
+ infoValue |= (tmp & ANI_SSM_RSN_KEY_DESC_VERS_MASK);
+
+ if (info->unicastFlag)
+ infoValue |= ANI_SSM_RSN_UNICAST_MASK;
+
+ tmp = info->keyId;
+ tmp = tmp << ANI_SSM_RSN_KEY_INDEX_OFFSET;
+ infoValue |= (tmp & ANI_SSM_RSN_KEY_INDEX_MASK);
+
+ if (info->installFlag)
+ infoValue |= ANI_SSM_RSN_INSTALL_MASK;
+
+ if (info->ackFlag)
+ infoValue |= ANI_SSM_RSN_ACK_MASK;
+
+ if (info->micFlag)
+ infoValue |= ANI_SSM_RSN_MIC_MASK;
+
+ if (info->secureFlag)
+ infoValue |= ANI_SSM_RSN_SECURE_MASK;
+
+ if (info->errorFlag)
+ infoValue |= ANI_SSM_RSN_ERROR_MASK;
+
+ if (info->requestFlag)
+ infoValue |= ANI_SSM_RSN_REQUEST_MASK;
+
+ if (info->encKeyDataFlag)
+ infoValue |= ANI_SSM_RSN_ENC_KEY_DATA_MASK;
+
+ retVal = aniAsfPacketAppend16(packet, infoValue);
+
+ return retVal;
+}
+
+
+static int
+writeRsnKeyMic(v_U32_t cryptHandle,
+ tAniPacket *eapolFrame,
+ tAniEapolRsnKeyDesc *rsnDesc,
+ v_U8_t *micKey,
+ v_U32_t micKeyLen)
+{
+ int retVal = ANI_OK;
+ int len;
+
+ v_U8_t *ptr = NULL;
+ v_U8_t *micPos = NULL;
+ v_U8_t result[VOS_DIGEST_SHA1_SIZE]; // Larger of the two
+
+ // Sanity check the arguments and return if no MIC generation is
+ // needed
+ if (micKey != NULL)
+ {
+ if (micKeyLen == 0 || !rsnDesc->info.micFlag)
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ "Supp MIC key provided but micKeyLen or micFlag is not set!\n");
+ VOS_ASSERT( 0 );
+ return ANI_E_ILLEGAL_ARG;
+ }
+ }
+ else {
+ if (rsnDesc->info.micFlag)
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ "Supp micFlag is set but MIC key not provided!\n");
+ VOS_ASSERT( 0 );
+ return ANI_E_ILLEGAL_ARG;
+ }
+ // Normal condition where MIC is not desired by the caller
+ return ANI_OK;
+ }
+
+ len = aniAsfPacketGetBytes(eapolFrame, &ptr);
+ if( !ANI_IS_STATUS_SUCCESS( len ) )
+ {
+ return len;
+ }
+
+ micPos = ptr + ANI_SSM_RSN_KEY_MIC_OFFSET + SNAP_HEADER_SIZE;
+
+ // Clear the MIC field in the packet before the MIC computation
+ vos_mem_zero( micPos, VOS_DIGEST_MD5_SIZE);
+
+ // Skip to the EAPOL version field for MIC computation
+ ptr += EAPOL_VERSION_POS + SNAP_HEADER_SIZE;
+ len -= (EAPOL_VERSION_POS + SNAP_HEADER_SIZE);
+
+ if (rsnDesc->info.keyDescVers == ANI_EAPOL_KEY_DESC_VERS_AES)
+ {
+ if( VOS_IS_STATUS_SUCCESS( vos_sha1_hmac_str(cryptHandle, ptr, len, micKey, micKeyLen, result) ) )
+ {
+ retVal = ANI_OK;
+ }
+ else
+ {
+ retVal = ANI_ERROR;
+ }
+ }
+ else {
+ VOS_ASSERT( 0 );
+ retVal = ANI_E_ILLEGAL_ARG;
+ }
+
+ if (retVal == ANI_OK)
+ {
+ // Copy only 16B which is the smaller of the two and the same as
+ // ANI_EAPOL_KEY_RSN_MIC_SIZE
+ vos_mem_copy(micPos, result, VOS_DIGEST_MD5_SIZE);
+ }
+
+ return retVal;
+}
+
+/**
+ * aniEapolKeyCheckMic
+ *
+ * @param eapolFrame the complete EAPOL-Key packet
+ * @param descType the key descriptor type
+ * @param keyDescData the key descriptor
+ * @param micKey the MIC key
+ * @param micKeyLen the number of bytes in the MIC key
+ *
+ * @return ANI_OK if the operation succeeds; ANI_E_MIC_FAILED if the
+ * MIC check fails.
+ */
+int
+aniEapolKeyCheckMic(v_U32_t cryptHandle,
+ tAniPacket *eapolFrame,
+ int descType,
+ void *keyDescData,
+ v_U8_t *micKey,
+ v_U32_t micKeyLen)
+{
+ if (descType == ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW)
+ {
+ return checkRsnKeyMic(cryptHandle, eapolFrame, keyDescData, micKey, micKeyLen);
+ }
+ else {
+ VOS_ASSERT( 0 );
+ return ANI_E_ILLEGAL_ARG;
+ }
+}
+
+
+static int
+checkRsnKeyMic(v_U32_t cryptHandle,
+ tAniPacket *eapolFrame,
+ tAniEapolRsnKeyDesc *rsnDesc,
+ v_U8_t *micKey,
+ v_U32_t micKeyLen)
+{
+ int retVal = ANI_ERROR;
+ int len;
+
+ v_U8_t *ptr = NULL;
+ v_U8_t *micPos = NULL;
+
+ v_U8_t result[VOS_DIGEST_SHA1_SIZE]; // Larger of the two
+ v_U8_t incomingMic[ANI_EAPOL_KEY_RSN_MIC_SIZE];
+
+ if (!rsnDesc->info.micFlag)
+ {
+ VOS_ASSERT( 0 );
+ return ANI_E_ILLEGAL_ARG;
+ }
+
+ len = aniAsfPacketGetBytes(eapolFrame, &ptr);
+ if( ANI_IS_STATUS_SUCCESS( len ) )
+ {
+ micPos = ptr + ANI_SSM_RSN_KEY_MIC_OFFSET;
+
+ // Skip to the EAPOL version field for MIC computation
+ ptr += EAPOL_VERSION_POS;
+ len -= EAPOL_VERSION_POS;
+
+ // Copy existing MIC to temporary location and zero it out
+ vos_mem_copy( incomingMic, micPos, ANI_EAPOL_KEY_RSN_MIC_SIZE );
+ vos_mem_zero( micPos, ANI_EAPOL_KEY_RSN_MIC_SIZE );
+
+ if (rsnDesc->info.keyDescVers == ANI_EAPOL_KEY_DESC_VERS_AES)
+ {
+ if( VOS_IS_STATUS_SUCCESS( vos_sha1_hmac_str(cryptHandle, ptr, len, micKey, micKeyLen, result) ) )
+ {
+ retVal = ANI_OK;
+ }
+ }
+ else {
+ VOS_ASSERT( 0 );
+ retVal = ANI_E_ILLEGAL_ARG;
+ }
+
+ if (retVal == ANI_OK)
+ {
+ if ( !vos_mem_compare(incomingMic, result, ANI_EAPOL_KEY_RSN_MIC_SIZE))
+ {
+ retVal = ANI_E_MIC_FAILED;
+ }
+ }
+ }
+
+ return retVal;
+}
+
+/**
+ * aniEapolKeyFreeDesc
+ *
+ * Frees the EAPOL key descriptor and the key bytes contained within it.
+ *
+ * @param descType the key descriptor type
+ * @param keyDescData the key descriptor
+ *
+ * @return ANI_OK if the operation succeeds
+ */
+int
+aniEapolKeyFreeDesc(int descType, void *keyDescData)
+{
+ tAniEapolRsnKeyDesc *rsnDesc;
+
+ if( keyDescData )
+ {
+ if ((descType == ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW)
+ || (descType == ANI_EAPOL_KEY_DESC_TYPE_RSN))
+ {
+
+ rsnDesc = (tAniEapolRsnKeyDesc *) keyDescData;
+ if (rsnDesc->keyData != NULL)
+ vos_mem_free(rsnDesc->keyData);
+
+ }
+ else {
+
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ "Supp asked to free illegal type: %d\n", descType);
+
+ }
+
+ vos_mem_free(keyDescData);
+ }
+
+ return ANI_OK;
+}
+
+v_U8_t *
+aniEapolType2Str(v_U8_t type)
+{
+ switch (type)
+ {
+ case ANI_EAPOL_TYPE_PACKET:
+ return (v_U8_t *)ANI_EAPOL_TYPE_PACKET_STR;
+ break;
+ case ANI_EAPOL_TYPE_START:
+ return (v_U8_t *)ANI_EAPOL_TYPE_START_STR;
+ break;
+ case ANI_EAPOL_TYPE_LOGOFF:
+ return (v_U8_t *)ANI_EAPOL_TYPE_LOGOFF_STR;
+ break;
+ case ANI_EAPOL_TYPE_KEY:
+ return (v_U8_t *)ANI_EAPOL_TYPE_KEY_STR;
+ break;
+ case ANI_EAPOL_TYPE_ASF_ALERT:
+ return (v_U8_t *)ANI_EAPOL_TYPE_ASF_ALERT_STR;
+ break;
+ default:
+ return (v_U8_t *)ANI_EAPOL_TYPE_UNKNOWN_STR;
+ break;
+ }
+}
+
+
+void bapRsnEapolHandler( v_PVOID_t pvFsm, tAniPacket *packet, v_BOOL_t fIsAuth )
+{
+ int retVal;
+ v_U8_t *dstMac = NULL;
+ v_U8_t *srcMac = NULL;
+ v_U8_t *type = NULL;
+
+ retVal = aniEapolParse(packet, &dstMac, &srcMac, &type);
+ if ( retVal >= 0 )
+ {
+ retVal = ANI_OK;
+
+ // Sanity check that a PAE role has been assigned to it,
+ // and then dispatch to the appropriate handler
+
+ if( fIsAuth )
+ {
+ tAuthRsnFsm *fsm = (tAuthRsnFsm *)pvFsm;
+ authEapolHandler( fsm, packet, dstMac, srcMac, type );
+ }
+ else
+ {
+ tSuppRsnFsm *fsm = (tSuppRsnFsm *)pvFsm;
+ suppEapolHandler(fsm, packet, dstMac, srcMac, type);
+ } // switch statement
+ } // Successfully parsed EAPOL
+ else
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ "eapolHandler Received bad EAPOL message of len %d (status=%d)\n",
+ aniAsfPacketGetLen(packet), retVal );
+ }
+ aniAsfPacketFree( packet );
+}
+
+
+int bapRsnFormPktFromVosPkt( tAniPacket **ppPacket, vos_pkt_t *pVosPacket )
+{
+ int retVal = ANI_ERROR;
+ VOS_STATUS status;
+ v_U16_t uPktLen;
+#define BAP_RSN_SNAP_TYPE_OFFSET 20
+#define BAP_RSN_ETHERNET_3_HEADER_LEN 22
+ v_U8_t *pFrame;
+ tAniPacket *pAniPacket = NULL;
+
+ do
+ {
+ status = vos_pkt_get_packet_length( pVosPacket, &uPktLen );
+ if( !VOS_IS_STATUS_SUCCESS(status) ) break;
+ if( (uPktLen < BAP_RSN_ETHERNET_3_HEADER_LEN) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ " authRsnRxFrameHandler receive eapol packet size (%d) too small (%d)\n",
+ uPktLen, BAP_RSN_ETHERNET_3_HEADER_LEN );
+ break;
+ }
+ status = vos_pkt_peek_data( pVosPacket, 0, (v_VOID_t *)&pFrame, uPktLen );
+ if( !VOS_IS_STATUS_SUCCESS(status) ) break;
+ retVal = aniAsfPacketAllocateExplicit(&pAniPacket, uPktLen, 0 );
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ " authRsnRxFrameHandler failed to get buffer size (%d) \n",
+ uPktLen );
+ break;
+ }
+ aniAsfPacketEmptyExplicit( pAniPacket, 0 );
+ pFrame[ETHER_PROTO_POS] = pFrame[BAP_RSN_SNAP_TYPE_OFFSET];
+ pFrame[ETHER_PROTO_POS + 1] = pFrame[BAP_RSN_SNAP_TYPE_OFFSET + 1];
+ //push ethernet II header in
+ retVal = aniAsfPacketAppendBuffer( pAniPacket, pFrame, ETHER_PROTO_POS + 2 );
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break;
+ //Get the rest of the data in
+ uPktLen -= BAP_RSN_ETHERNET_3_HEADER_LEN;
+ VOS_ASSERT( uPktLen > 0 );
+ retVal = aniAsfPacketAppendBuffer( pAniPacket, pFrame + BAP_RSN_ETHERNET_3_HEADER_LEN,
+ uPktLen );
+ if( !ANI_IS_STATUS_SUCCESS( retVal ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
+ " authRsnRxFrameHandler cannot retrieve eapol payload size (%d)\n",
+ uPktLen );
+ break;
+ }
+ }while( 0 );
+
+ if( ANI_IS_STATUS_SUCCESS( retVal ) )
+ {
+ *ppPacket = pAniPacket;
+ }
+ else if( pAniPacket )
+ {
+ aniAsfPacketFree( pAniPacket );
+ }
+
+ return retVal;
+}
+
+