blob: 9f36857b30226b3bc4e428eeecdf146de33d7a82 [file] [log] [blame]
/*
* Copyright (c) 2012-2016, 2018 The Linux Foundation. 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*============================================================================
FILE: vos_utils.c
OVERVIEW: This source file contains definitions for vOS crypto APIs
The four APIs mentioned in this file are used for
initializing, and de-initializing a crypto context, and
obtaining truly random data (for keys), as well as
SHA1 HMAC, and AES encrypt and decrypt routines.
The routines include:
vos_crypto_init() - Initializes Crypto module
vos_crypto_deinit() - De-initializes Crypto module
vos_rand_get_bytes() - Generates random byte
vos_sha1_hmac_str() - Generate the HMAC-SHA1 of a string given a key
vos_encrypt_AES() - Generate AES Encrypted byte stream
vos_decrypt_AES() - Decrypts an AES Encrypted byte stream
DEPENDENCIES:
============================================================================*/
/*============================================================================
EDIT HISTORY FOR MODULE
============================================================================*/
/*----------------------------------------------------------------------------
* Include Files
* -------------------------------------------------------------------------*/
#include "vos_trace.h"
#include "vos_utils.h"
#include "vos_memory.h"
#include <linux/wcnss_wlan.h>
#include <linux/err.h>
#include <linux/random.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/completion.h>
#include <linux/vmalloc.h>
#include <crypto/hash.h>
#include "vos_diag_core_event.h"
/*----------------------------------------------------------------------------
* Preprocessor Definitions and Constants
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Type Declarations
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Global Data Definitions
* -------------------------------------------------------------------------*/
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,19,0)) || \
defined(WLAN_BTAMP_FEATURE)
extern struct crypto_ahash *wcnss_wlan_crypto_alloc_ahash(const char *alg_name,
unsigned int type,
unsigned int mask);
extern int wcnss_wlan_crypto_ahash_digest(struct ahash_request *req);
extern void wcnss_wlan_crypto_free_ahash(struct crypto_ahash *tfm);
extern int wcnss_wlan_crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen);
extern struct crypto_ablkcipher *wcnss_wlan_crypto_alloc_ablkcipher(const char *alg_name,
u32 type, u32 mask);
extern void wcnss_wlan_crypto_free_ablkcipher(struct crypto_ablkcipher *tfm);
extern void wcnss_wlan_ablkcipher_request_free(struct ablkcipher_request *req);
/*----------------------------------------------------------------------------
* Static Variable Definitions
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
Function Definitions and Documentation
* -------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------
\brief vos_crypto_init() - Initializes Crypto module
The vos_crypto_init() function initializes Crypto module.
\param phCryptProv - pointer to the Crypt handle
\return VOS_STATUS_SUCCESS - Successfully generated random memory.
VOS_STATUS_E_FAULT - pbBuf is an invalid pointer.
VOS_STATUS_E_FAILURE - default return value if it fails due to
unknown reasons
***VOS_STATUS_E_RESOURCES - System resources (other than memory)
are unavailable
\sa
( *** return value not considered yet )
--------------------------------------------------------------------------*/
VOS_STATUS vos_crypto_init( v_U32_t *phCryptProv )
{
VOS_STATUS uResult = VOS_STATUS_E_FAILURE;
// This implementation doesn't require a crypto context
*phCryptProv = 0;
uResult = VOS_STATUS_SUCCESS;
return ( uResult );
}
VOS_STATUS vos_crypto_deinit( v_U32_t hCryptProv )
{
VOS_STATUS uResult = VOS_STATUS_E_FAILURE;
// CryptReleaseContext succeeded
uResult = VOS_STATUS_SUCCESS;
return ( uResult );
}
#endif
/*--------------------------------------------------------------------------
\brief vos_rand_get_bytes() - Generates random byte
The vos_rand_get_bytes() function generate random bytes.
Buffer should be allocated before calling vos_rand_get_bytes().
Attempting to initialize an already initialized lock results in
a failure.
\param lock - pointer to the opaque lock object to initialize
\return VOS_STATUS_SUCCESS - Successfully generated random memory.
VOS_STATUS_E_FAULT - pbBuf is an invalid pointer.
VOS_STATUS_E_FAILURE - default return value if it fails due to
unknown reasons
***VOS_STATUS_E_RESOURCES - System resources (other than memory)
are unavailable
\sa
( *** return value not considered yet )
--------------------------------------------------------------------------*/
VOS_STATUS vos_rand_get_bytes( v_U32_t cryptHandle, v_U8_t *pbBuf, v_U32_t numBytes )
{
VOS_STATUS uResult = VOS_STATUS_E_FAILURE;
//v_UINT_t uCode;
// HCRYPTPROV hCryptProv = (HCRYPTPROV) cryptHandle;
//check for invalid pointer
if ( NULL == pbBuf )
{
uResult = VOS_STATUS_E_FAULT;
return ( uResult );
}
//#if 0
// get_random_bytes() is a void procedure
get_random_bytes( pbBuf, numBytes);
// "Random sequence generated."
uResult = VOS_STATUS_SUCCESS;
//#endif
return ( uResult );
}
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,19,0)) || \
defined(WLAN_BTAMP_FEATURE)
/**
* vos_sha1_hmac_str
*
* FUNCTION:
* Generate the HMAC-SHA1 of a string given a key.
*
* LOGIC:
* Standard HMAC processing from RFC 2104. The code is provided in the
* appendix of the RFC.
*
* ASSUMPTIONS:
* The RFC is correct.
*
* @param text text to be hashed
* @param textLen length of text
* @param key key to use for HMAC
* @param keyLen length of key
* @param digest holds resultant SHA1 HMAC (20B)
*
* @return VOS_STATUS_SUCCSS if the operation succeeds
*
*/
struct hmac_sha1_result {
struct completion completion;
int err;
};
static void hmac_sha1_complete(struct crypto_async_request *req, int err)
{
struct hmac_sha1_result *r = req->data;
if (err == -EINPROGRESS)
return;
r->err = err;
complete(&r->completion);
}
int hmac_sha1(v_U8_t *key, v_U8_t ksize, char *plaintext, v_U8_t psize,
v_U8_t *output, v_U8_t outlen)
{
int ret = 0;
struct crypto_ahash *tfm;
struct scatterlist sg;
struct ahash_request *req;
struct hmac_sha1_result tresult;
void *hash_buff = NULL;
unsigned char hash_result[64];
int i;
memset(output, 0, outlen);
init_completion(&tresult.completion);
tfm = wcnss_wlan_crypto_alloc_ahash("hmac(sha1)", CRYPTO_ALG_TYPE_AHASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
if (IS_ERR(tfm)) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_alloc_ahash failed");
ret = PTR_ERR(tfm);
goto err_tfm;
}
req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "failed to allocate request for hmac(sha1)");
ret = -ENOMEM;
goto err_req;
}
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
hmac_sha1_complete, &tresult);
hash_buff = kzalloc(psize, GFP_KERNEL);
if (!hash_buff) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "failed to kzalloc hash_buff");
ret = -ENOMEM;
goto err_hash_buf;
}
memset(hash_result, 0, 64);
vos_mem_copy(hash_buff, plaintext, psize);
sg_init_one(&sg, hash_buff, psize);
if (ksize) {
crypto_ahash_clear_flags(tfm, ~0);
ret = wcnss_wlan_crypto_ahash_setkey(tfm, key, ksize);
if (ret) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_ahash_setkey failed");
goto err_setkey;
}
}
ahash_request_set_crypt(req, &sg, hash_result, psize);
ret = wcnss_wlan_crypto_ahash_digest(req);
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "ret 0x%x", ret);
switch (ret) {
case 0:
for (i=0; i< outlen; i++)
output[i] = hash_result[i];
break;
case -EINPROGRESS:
case -EBUSY:
ret = wait_for_completion_interruptible(&tresult.completion);
if (!ret && !tresult.err) {
for (i=0; i< outlen; i++)
output[i] = hash_result[i];
INIT_COMPLETION(tresult.completion);
break;
} else {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "wait_for_completion_interruptible failed");
if (!ret)
ret = tresult.err;
goto out;
}
default:
goto out;
}
out:
err_setkey:
kfree(hash_buff);
err_hash_buf:
ahash_request_free(req);
err_req:
wcnss_wlan_crypto_free_ahash(tfm);
err_tfm:
return ret;
}
VOS_STATUS vos_sha1_hmac_str(v_U32_t cryptHandle, /* Handle */
v_U8_t *pText, /* pointer to data stream */
v_U32_t textLen, /* length of data stream */
v_U8_t *pKey, /* pointer to authentication key */
v_U32_t keyLen, /* length of authentication key */
v_U8_t digest[VOS_DIGEST_SHA1_SIZE])/* caller digest to be filled in */
{
int ret = 0;
ret = hmac_sha1(
pKey, //v_U8_t *key,
(v_U8_t) keyLen, //v_U8_t ksize,
(char *)pText, //char *plaintext,
(v_U8_t) textLen, //v_U8_t psize,
digest, //v_U8_t *output,
VOS_DIGEST_SHA1_SIZE //v_U8_t outlen
);
if (ret != 0) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,"hmac_sha1() call failed");
return VOS_STATUS_E_FAULT;
}
return VOS_STATUS_SUCCESS;
}
/**
* vos_md5_hmac_str
*
* FUNCTION:
* Generate the HMAC-MD5 of a string given a key.
*
* LOGIC:
* Standard HMAC processing from RFC 2104. The code is provided in the
* appendix of the RFC.
*
* ASSUMPTIONS:
* The RFC is correct.
*
* @param text text to be hashed
* @param textLen length of text
* @param key key to use for HMAC
* @param keyLen length of key
* @param digest holds resultant MD5 HMAC (20B)
*
* @return VOS_STATUS_SUCCSS if the operation succeeds
*
*/
struct hmac_md5_result {
struct completion completion;
int err;
};
static void hmac_md5_complete(struct crypto_async_request *req, int err)
{
struct hmac_md5_result *r = req->data;
if (err == -EINPROGRESS)
return;
r->err = err;
complete(&r->completion);
}
int hmac_md5(v_U8_t *key, v_U8_t ksize, char *plaintext, v_U8_t psize,
v_U8_t *output, v_U8_t outlen)
{
int ret = 0;
struct crypto_ahash *tfm;
struct scatterlist sg;
struct ahash_request *req;
struct hmac_md5_result tresult = {.err = 0};
void *hash_buff = NULL;
unsigned char hash_result[64];
int i;
memset(output, 0, outlen);
init_completion(&tresult.completion);
tfm = wcnss_wlan_crypto_alloc_ahash("hmac(md5)", CRYPTO_ALG_TYPE_AHASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
if (IS_ERR(tfm)) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_alloc_ahash failed");
ret = PTR_ERR(tfm);
goto err_tfm;
}
req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "failed to allocate request for hmac(md5)");
ret = -ENOMEM;
goto err_req;
}
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
hmac_md5_complete, &tresult);
hash_buff = kzalloc(psize, GFP_KERNEL);
if (!hash_buff) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "failed to kzalloc hash_buff");
ret = -ENOMEM;
goto err_hash_buf;
}
memset(hash_result, 0, 64);
vos_mem_copy(hash_buff, plaintext, psize);
sg_init_one(&sg, hash_buff, psize);
if (ksize) {
crypto_ahash_clear_flags(tfm, ~0);
ret = wcnss_wlan_crypto_ahash_setkey(tfm, key, ksize);
if (ret) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_ahash_setkey failed");
goto err_setkey;
}
}
ahash_request_set_crypt(req, &sg, hash_result, psize);
ret = wcnss_wlan_crypto_ahash_digest(req);
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "ret 0x%x", ret);
switch (ret) {
case 0:
for (i=0; i< outlen; i++)
output[i] = hash_result[i];
break;
case -EINPROGRESS:
case -EBUSY:
ret = wait_for_completion_interruptible(&tresult.completion);
if (!ret && !tresult.err) {
for (i=0; i< outlen; i++)
output[i] = hash_result[i];
INIT_COMPLETION(tresult.completion);
break;
} else {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "wait_for_completion_interruptible failed");
if (!ret)
ret = tresult.err;
goto out;
}
default:
goto out;
}
out:
err_setkey:
kfree(hash_buff);
err_hash_buf:
ahash_request_free(req);
err_req:
wcnss_wlan_crypto_free_ahash(tfm);
err_tfm:
return ret;
}
VOS_STATUS vos_md5_hmac_str(v_U32_t cryptHandle, /* Handle */
v_U8_t *pText, /* pointer to data stream */
v_U32_t textLen, /* length of data stream */
v_U8_t *pKey, /* pointer to authentication key */
v_U32_t keyLen, /* length of authentication key */
v_U8_t digest[VOS_DIGEST_MD5_SIZE])/* caller digest to be filled in */
{
int ret = 0;
ret = hmac_md5(
pKey, //v_U8_t *key,
(v_U8_t) keyLen, //v_U8_t ksize,
(char *)pText, //char *plaintext,
(v_U8_t) textLen, //v_U8_t psize,
digest, //v_U8_t *output,
VOS_DIGEST_MD5_SIZE //v_U8_t outlen
);
if (ret != 0) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,"hmac_md5() call failed");
return VOS_STATUS_E_FAULT;
}
return VOS_STATUS_SUCCESS;
}
struct ecb_aes_result {
struct completion completion;
int err;
};
static void ecb_aes_complete(struct crypto_async_request *req, int err)
{
struct ecb_aes_result *r = req->data;
if (err == -EINPROGRESS)
return;
r->err = err;
complete(&r->completion);
}
/*--------------------------------------------------------------------------
\brief vos_encrypt_AES() - Generate AES Encrypted byte stream
The vos_encrypt_AES() function generates the encrypted byte stream for given text.
Buffer should be allocated before calling vos_rand_get_bytes().
Attempting to initialize an already initialized lock results in
a failure.
\param lock - pointer to the opaque lock object to initialize
\return VOS_STATUS_SUCCESS - Successfully generated random memory.
VOS_STATUS_E_FAULT - pbBuf is an invalid pointer.
VOS_STATUS_E_FAILURE - default return value if it fails due to
unknown reasons
***VOS_STATUS_E_RESOURCES - System resources (other than memory)
are unavailable
\sa
( *** return value not considered yet )
--------------------------------------------------------------------------*/
#define IV_SIZE_AES_128 16
#define KEY_SIZE_AES_128 16
#define AES_BLOCK_SIZE 16
VOS_STATUS vos_encrypt_AES(v_U32_t cryptHandle, /* Handle */
v_U8_t *pPlainText, /* pointer to data stream */
v_U8_t *pCiphertext,
v_U8_t *pKey) /* pointer to authentication key */
{
// VOS_STATUS uResult = VOS_STATUS_E_FAILURE;
struct ecb_aes_result result;
struct ablkcipher_request *req;
struct crypto_ablkcipher *tfm;
int ret = 0;
char iv[IV_SIZE_AES_128];
struct scatterlist sg_in;
struct scatterlist sg_out;
init_completion(&result.completion);
tfm = wcnss_wlan_crypto_alloc_ablkcipher( "cbc(aes)", 0, 0);
if (IS_ERR(tfm)) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_alloc_ablkcipher failed");
ret = PTR_ERR(tfm);
goto err_tfm;
}
req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
if (!req) {
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "Failed to allocate request for cbc(aes)");
ret = -ENOMEM;
goto err_req;
}
ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
ecb_aes_complete, &result);
crypto_ablkcipher_clear_flags(tfm, ~0);
ret = crypto_ablkcipher_setkey(tfm, pKey, KEY_SIZE_AES_128);
if (ret) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_cipher_setkey failed");
goto err_setkey;
}
memset(iv, 0, IV_SIZE_AES_128);
sg_init_one(&sg_in, pPlainText, AES_BLOCK_SIZE);
sg_init_one(&sg_out, pCiphertext, AES_BLOCK_SIZE);
ablkcipher_request_set_crypt(req, &sg_in, &sg_out, AES_BLOCK_SIZE, iv);
crypto_ablkcipher_encrypt(req);
// -------------------------------------
err_setkey:
wcnss_wlan_ablkcipher_request_free(req);
err_req:
wcnss_wlan_crypto_free_ablkcipher(tfm);
err_tfm:
//return ret;
if (ret != 0) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,"%s() call failed", __func__);
return VOS_STATUS_E_FAULT;
}
return VOS_STATUS_SUCCESS;
}
/*--------------------------------------------------------------------------
\brief vos_decrypt_AES() - Decrypts an AES Encrypted byte stream
The vos_decrypt_AES() function decrypts the encrypted byte stream.
Buffer should be allocated before calling vos_rand_get_bytes().
Attempting to initialize an already initialized lock results in
a failure.
\param lock - pointer to the opaque lock object to initialize
\return VOS_STATUS_SUCCESS - Successfully generated random memory.
VOS_STATUS_E_FAULT - pbBuf is an invalid pointer.
VOS_STATUS_E_FAILURE - default return value if it fails due to
unknown reasons
***VOS_STATUS_E_RESOURCES - System resources (other than memory)
are unavailable
\sa
( *** return value not considered yet )
--------------------------------------------------------------------------*/
VOS_STATUS vos_decrypt_AES(v_U32_t cryptHandle, /* Handle */
v_U8_t *pText, /* pointer to data stream */
v_U8_t *pDecrypted,
v_U8_t *pKey) /* pointer to authentication key */
{
// VOS_STATUS uResult = VOS_STATUS_E_FAILURE;
struct ecb_aes_result result;
struct ablkcipher_request *req;
struct crypto_ablkcipher *tfm;
int ret = 0;
char iv[IV_SIZE_AES_128];
struct scatterlist sg_in;
struct scatterlist sg_out;
init_completion(&result.completion);
tfm = wcnss_wlan_crypto_alloc_ablkcipher( "cbc(aes)", 0, 0);
if (IS_ERR(tfm)) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_alloc_ablkcipher failed");
ret = PTR_ERR(tfm);
goto err_tfm;
}
req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
if (!req) {
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "Failed to allocate request for cbc(aes)");
ret = -ENOMEM;
goto err_req;
}
ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
ecb_aes_complete, &result);
crypto_ablkcipher_clear_flags(tfm, ~0);
ret = crypto_ablkcipher_setkey(tfm, pKey, KEY_SIZE_AES_128);
if (ret) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_cipher_setkey failed");
goto err_setkey;
}
memset(iv, 0, IV_SIZE_AES_128);
sg_init_one(&sg_in, pText, AES_BLOCK_SIZE);
sg_init_one(&sg_out, pDecrypted, AES_BLOCK_SIZE);
ablkcipher_request_set_crypt(req, &sg_in, &sg_out, AES_BLOCK_SIZE, iv);
crypto_ablkcipher_decrypt(req);
// -------------------------------------
err_setkey:
wcnss_wlan_ablkcipher_request_free(req);
err_req:
wcnss_wlan_crypto_free_ablkcipher(tfm);
err_tfm:
//return ret;
if (ret != 0) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,"%s() call failed", __func__);
return VOS_STATUS_E_FAULT;
}
return VOS_STATUS_SUCCESS;
}
#endif
v_U8_t vos_chan_to_band(v_U32_t chan)
{
if (chan <= VOS_24_GHZ_CHANNEL_14)
return VOS_BAND_2GHZ;
return VOS_BAND_5GHZ;
}
void vos_get_wlan_unsafe_channel(v_U16_t *unsafeChannelList,
v_U16_t buffer_size, v_U16_t *unsafeChannelCount)
{
/* Get unsafe channel list from cached location */
wcnss_get_wlan_unsafe_channel(unsafeChannelList, buffer_size,
unsafeChannelCount);
}
#include <linux/skbuff.h>
#include "vos_timer.h"
#include "i_vos_packet.h"
#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
#define DXE_DATA_MAGIC_NO 0x010
#define DXE_MGMT_MAGIC_NO 0x011
//Define gRoamDelayMetaInfo
tRoamDelayMetaInfo gRoamDelayMetaInfo = {0};
tRoamDelayMetaInfo *gpRoamDelayTable = NULL;
v_BOOL_t gRoamDelayCurrentIndex = 0;
#define VOS_ETHERTYPE_802_1_X ( 0x888E )
#define VOS_ETHERTYPE_802_1_X_SIZE ( 2 )
//802.3 frame header have SRC MAC (6), DST(6),next will PROTOCOL type
#define VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_3_PKT ( 12 )
//802.11 header wil have 26 byte (Inculding QoS Info)
//8Byte LLC / SNAP header in which last two byte will be PROTOCOL type
//So offset will 32 if it is QoS data pkt else it will be 30
#define VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_11_PKT ( 32 )
#define VOS_QOS_DATA_VALUE ( 0x88 )
#define VOS_NON_QOS_DATA_VALUE ( 0x80 )
//802.11 header wil have 24 byte excluding qos
#define VOS_802_11_HEADER_SIZE ( 24 )
#define VOS_QOS_SIZE ( 2 )
#define VOS_LLC_HEADER_SIZE (8)
#define VOS_IP_HEADER_SIZE (20)
#define VOS_TCP_MIN_HEADER_SIZE (20)
#define VOS_DEF_PKT_STATS_LEN_TO_COPY \
(VOS_802_11_HEADER_SIZE + VOS_LLC_HEADER_SIZE \
+ VOS_IP_HEADER_SIZE + VOS_TCP_MIN_HEADER_SIZE)
// DHCP Port number
#define VOS_DHCP_SOURCE_PORT 0x4400
#define VOS_DHCP_DESTINATION_PORT 0x4300
// Frame Type definitions
#define VOS_MAC_MGMT_FRAME 0x0
#define VOS_MAC_CTRL_FRAME 0x1
#define VOS_MAC_DATA_FRAME 0x2
#define MONITOR_STOP 0x0
#define MONITOR_START 0x1
#define MONITOR_EAPOL_DONE 0x2
#define MONITOR_FIRST_DATA_DONE 0x4
v_BOOL_t vos_skb_is_eapol(struct sk_buff *skb,
v_SIZE_t pktOffset,
v_SIZE_t numBytes)
{
void *pBuffer = NULL;
v_BOOL_t fEAPOL = VOS_FALSE;
// Validate the skb
if (unlikely(NULL == skb))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"vos_skb_is_eapol [%d]: NULL skb", __LINE__);
return VOS_FALSE;
}
// check for overflow
if (unlikely((pktOffset + numBytes) > skb->len))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"vos_skb_is_eapol [%d]: Packet overflow, offset %d size %d len %d",
__LINE__, pktOffset, numBytes, skb->len);
return VOS_FALSE;
}
//check for the Qos Data, if Offset length is more 12.
//it means it will 802.11 header skb
if((pktOffset > VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_3_PKT)
&& (skb->data[0] == VOS_NON_QOS_DATA_VALUE))
{
// reduced 2 byte of Qos ctrl field in DOT11 header
pktOffset = pktOffset - 2;
}
pBuffer = &skb->data[pktOffset];
if (pBuffer && vos_be16_to_cpu( *(unsigned short*)pBuffer ) == VOS_ETHERTYPE_802_1_X )
{
fEAPOL = VOS_TRUE;
}
return fEAPOL;
}
v_BOOL_t vos_roam_delay_stats_init(void)
{
if (gpRoamDelayTable == NULL)
{
gpRoamDelayTable = vmalloc(sizeof(tRoamDelayMetaInfo) * ROAM_DELAY_TABLE_SIZE);
if (gpRoamDelayTable == NULL)
{
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "Memory allocation failed");
return VOS_FALSE;
}
}
else
{
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, "Memory is already allocated");
return VOS_FALSE;
}
return VOS_TRUE;
}
v_BOOL_t vos_roam_delay_stats_deinit(void)
{
if (gpRoamDelayTable != NULL)
{
vfree(gpRoamDelayTable);
gpRoamDelayTable = NULL;
}
else
{
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO, "Memory is already freed");
return VOS_FALSE;
}
return VOS_TRUE;
}
void vos_record_roam_event(enum e_roaming_event roam_event, void *pBuff, v_ULONG_t buff_len)
{
if (gpRoamDelayTable == NULL)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"Roam delay table is not initialized\n");
return;
}
switch(roam_event)
{
case e_HDD_DISABLE_TX_QUEUE:
gRoamDelayMetaInfo.hdd_monitor_tx = MONITOR_STOP;
gRoamDelayMetaInfo.disable_tx_queues_time = vos_timer_get_system_time();
break;
case e_SME_PREAUTH_REASSOC_START:
gRoamDelayMetaInfo.preauth_reassoc_start_time = vos_timer_get_system_time();
break;
case e_SME_PREAUTH_CALLBACK_HIT:
gRoamDelayMetaInfo.preauth_cb_time = vos_timer_get_system_time();
break;
case e_SME_ISSUE_REASSOC_REQ:
gRoamDelayMetaInfo.issue_reassoc_req_time = vos_timer_get_system_time();
//HACK buff len will carry the AuthType
gRoamDelayMetaInfo.hdd_auth_type = buff_len;
break;
case e_LIM_SEND_REASSOC_REQ:
gRoamDelayMetaInfo.send_reassoc_req_time = vos_timer_get_system_time();
//we can enable the rx eapol monitoring ASAP we send the REASSOC REQ Because
//there is very less delay in between REASSOC RSP and M1 Sent by the AP
gRoamDelayMetaInfo.hdd_monitor_rx = MONITOR_START;
gRoamDelayMetaInfo.dxe_monitor_rx = MONITOR_START;
break;
case e_CACHE_ROAM_PEER_MAC:
vos_mem_copy(&gRoamDelayMetaInfo.peer_mac_addr, pBuff, buff_len);
break;
case e_HDD_SEND_REASSOC_RSP:
gRoamDelayMetaInfo.hdd_sendassoc_rsp_time = vos_timer_get_system_time();
break;
case e_SME_DISASSOC_ISSUE:
gRoamDelayMetaInfo.disassoc_issue_time = vos_timer_get_system_time();
break;
case e_SME_DISASSOC_COMPLETE:
gRoamDelayMetaInfo.disassoc_comp_time = vos_timer_get_system_time();
break;
case e_LIM_ADD_BS_REQ:
gRoamDelayMetaInfo.lim_add_bss_req_time = vos_timer_get_system_time();
break;
case e_LIM_ADD_BS_RSP:
gRoamDelayMetaInfo.lim_add_bss_rsp_time = vos_timer_get_system_time();
break;
case e_HDD_ENABLE_TX_QUEUE:
gRoamDelayMetaInfo.hdd_monitor_tx = MONITOR_START;
gRoamDelayMetaInfo.enable_tx_queues_reassoc_time = vos_timer_get_system_time();
break;
case e_HDD_SET_PTK_REQ:
gRoamDelayMetaInfo.set_ptk_roam_key_time = vos_timer_get_system_time();
break;
case e_HDD_SET_GTK_REQ:
gRoamDelayMetaInfo.set_gtk_roam_key_time = vos_timer_get_system_time();
break;
case e_HDD_SET_PTK_RSP:
gRoamDelayMetaInfo.complete_ptk_roam_key_time = vos_timer_get_system_time();
//vos_mem_copy(&gRoamDelayMetaInfo.peer_mac_addr, pBuff, buff_len);
break;
case e_HDD_SET_GTK_RSP:
gRoamDelayMetaInfo.complete_gtk_roam_key_time = vos_timer_get_system_time();
break;
case e_TL_FIRST_XMIT_TIME:
if(gRoamDelayMetaInfo.log_tl)
{
gRoamDelayMetaInfo.tl_fetch_pkt_time = vos_timer_get_system_time();
gRoamDelayMetaInfo.log_tl = VOS_FALSE;
}
break;
case e_HDD_FIRST_XMIT_TIME:
if(gRoamDelayMetaInfo.hdd_monitor_tx != MONITOR_STOP)
{
struct sk_buff *skb = (struct sk_buff *)pBuff;
if(!skb)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"event e_HDD_FIRST_XMIT_TIME skb is null");
return;
}
if((gRoamDelayMetaInfo.hdd_auth_type == eVOS_AUTH_TYPE_RSN_PSK) ||
(gRoamDelayMetaInfo.hdd_auth_type == eVOS_AUTH_TYPE_WPA_PSK))
{
//Hdd xmit will have only 802.3 pkt so offset will pass as accordingly
if(vos_skb_is_eapol(skb, VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_3_PKT,
VOS_ETHERTYPE_802_1_X_SIZE) == VOS_TRUE)
{
if(gRoamDelayMetaInfo.hdd_eapol_m2 == 0)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"HDD XMIT m2");
gRoamDelayMetaInfo.hdd_eapol_m2 = vos_timer_get_system_time();
gRoamDelayMetaInfo.dxe_monitor_tx = MONITOR_START;
}
else if((gRoamDelayMetaInfo.hdd_eapol_m2) && (gRoamDelayMetaInfo.hdd_eapol_m4 == 0))
{
gRoamDelayMetaInfo.hdd_eapol_m4 = vos_timer_get_system_time();
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"HDD XMIT m4");
gRoamDelayMetaInfo.hdd_monitor_tx = MONITOR_EAPOL_DONE;
//We should return from here so can cache the time for first data pkt
return;
}
}
}
else
{
gRoamDelayMetaInfo.hdd_monitor_tx = MONITOR_EAPOL_DONE;
gRoamDelayMetaInfo.dxe_monitor_tx = MONITOR_START;
}
//Eapol is done it must be first data frame capture it
if(gRoamDelayMetaInfo.hdd_monitor_tx == MONITOR_EAPOL_DONE)
{
gRoamDelayMetaInfo.hdd_first_pkt_len = 50;
gRoamDelayMetaInfo.hdd_first_xmit_time = vos_timer_get_system_time();
gRoamDelayMetaInfo.log_tl = VOS_TRUE;
gRoamDelayMetaInfo.hdd_monitor_tx = MONITOR_STOP;
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"HDD %s XMIT first data frame after roaming", __func__);
if(skb->len < gRoamDelayMetaInfo.hdd_first_pkt_len)
gRoamDelayMetaInfo.hdd_first_pkt_len = skb->len;
vos_mem_copy(&gRoamDelayMetaInfo.hdd_first_pkt_data,
skb->data,gRoamDelayMetaInfo.hdd_first_pkt_len);
}
}
break;
case e_HDD_RX_PKT_CBK_TIME:
if(gRoamDelayMetaInfo.hdd_monitor_rx != MONITOR_STOP)
{
struct sk_buff *skb = (struct sk_buff *)pBuff;
if(!skb)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"event e_HDD_RX_PKT_CBK_TIME skb is null");
return;
}
if((gRoamDelayMetaInfo.hdd_auth_type == eVOS_AUTH_TYPE_RSN_PSK) ||
(gRoamDelayMetaInfo.hdd_auth_type == eVOS_AUTH_TYPE_WPA_PSK))
{
if(vos_skb_is_eapol(skb, VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_3_PKT,
VOS_ETHERTYPE_802_1_X_SIZE) == VOS_TRUE)
{
if(gRoamDelayMetaInfo.hdd_eapol_m1 == 0)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"HDD recv m1");
gRoamDelayMetaInfo.hdd_eapol_m1 = vos_timer_get_system_time();
}
else if((gRoamDelayMetaInfo.hdd_eapol_m1) && (gRoamDelayMetaInfo.hdd_eapol_m3 == 0))
{
gRoamDelayMetaInfo.hdd_eapol_m3 = vos_timer_get_system_time();
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"HDD recv m3");
gRoamDelayMetaInfo.hdd_monitor_rx = MONITOR_EAPOL_DONE;
}
}
}
else
{
gRoamDelayMetaInfo.hdd_monitor_rx = MONITOR_EAPOL_DONE;
}
if(gRoamDelayMetaInfo.hdd_monitor_rx == MONITOR_EAPOL_DONE)
{
gRoamDelayMetaInfo.hdd_monitor_rx = MONITOR_STOP;
}
}
break;
case e_DXE_RX_PKT_TIME:
if(gRoamDelayMetaInfo.dxe_monitor_rx != MONITOR_STOP)
{
vos_pkt_t *vos_pkt = NULL;
struct sk_buff *skb = NULL;
vos_pkt = (vos_pkt_t *)pBuff;
if(!vos_pkt)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"event e_DXE_RX_PKT_TIME vos_pkt is null");
return;
}
skb = vos_pkt->pSkb;
if(!skb)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"event e_DXE_RX_PKT_TIME skb is null");
return;
}
//DXE can RECV MGMT and DATA frame, we are interetsed in only DATA frame
if(buff_len & VOS_MAC_DATA_FRAME)
{
if((gRoamDelayMetaInfo.hdd_auth_type == eVOS_AUTH_TYPE_RSN_PSK) ||
(gRoamDelayMetaInfo.hdd_auth_type == eVOS_AUTH_TYPE_WPA_PSK))
{
if(vos_skb_is_eapol(skb, VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_11_PKT,
VOS_ETHERTYPE_802_1_X_SIZE) == VOS_TRUE)
{
if(gRoamDelayMetaInfo.dxe_eapol_m1 == 0)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"DXE recv m1");
gRoamDelayMetaInfo.dxe_eapol_m1 = vos_timer_get_system_time();
}
else if((gRoamDelayMetaInfo.dxe_eapol_m1) && (gRoamDelayMetaInfo.dxe_eapol_m3 == 0))
{
gRoamDelayMetaInfo.dxe_eapol_m3 = vos_timer_get_system_time();
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"DXE recv m3");
gRoamDelayMetaInfo.dxe_monitor_rx = MONITOR_EAPOL_DONE;
}
}
}
else
{
gRoamDelayMetaInfo.dxe_monitor_rx = MONITOR_EAPOL_DONE;
}
if(gRoamDelayMetaInfo.dxe_monitor_rx == MONITOR_EAPOL_DONE)
{
gRoamDelayMetaInfo.dxe_monitor_rx = MONITOR_STOP;
}
}
/*
else
{
printk("e_DXE_RX_PKT_TIME dump mgmt frames");
vos_trace_hex_dump( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, &skb->data[0], skb->len);
}
*/
}
break;
case e_DXE_FIRST_XMIT_TIME:
if(gRoamDelayMetaInfo.dxe_monitor_tx != MONITOR_STOP)
{
vos_pkt_t *vos_pkt = NULL;
struct sk_buff *skb = NULL;
vos_pkt = (vos_pkt_t *)pBuff;
if(!vos_pkt)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"event e_DXE_FIRST_XMIT_TIME vos_pkt is null");
return;
}
skb = vos_pkt->pSkb;
if(!skb)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"event e_DXE_FIRST_XMIT_TIME skb is null");
return;
}
//DXE can Txmit MGMT and DATA frame, we are interetsed in only DATA frame
if(buff_len & VOS_MAC_DATA_FRAME)
{
if((gRoamDelayMetaInfo.hdd_auth_type == eVOS_AUTH_TYPE_RSN_PSK) ||
(gRoamDelayMetaInfo.hdd_auth_type == eVOS_AUTH_TYPE_WPA_PSK))
{
if(vos_skb_is_eapol(skb, VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_11_PKT,
VOS_ETHERTYPE_802_1_X_SIZE) == VOS_TRUE)
{
if(gRoamDelayMetaInfo.dxe_eapol_m2 == 0)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"DXE XMIT m2");
gRoamDelayMetaInfo.dxe_eapol_m2 = vos_timer_get_system_time();
}
else if((gRoamDelayMetaInfo.dxe_eapol_m2) && (gRoamDelayMetaInfo.dxe_eapol_m4 == 0))
{
gRoamDelayMetaInfo.dxe_eapol_m4 = vos_timer_get_system_time();
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"DXE XMIT m4");
gRoamDelayMetaInfo.dxe_monitor_tx = MONITOR_EAPOL_DONE;
//We should return from here so can cache the time for first data pkt
return;
}
}
}
else
{
gRoamDelayMetaInfo.dxe_monitor_tx = MONITOR_EAPOL_DONE;
}
//HACK buff len is getting used as FRAME TYPE
if(gRoamDelayMetaInfo.dxe_monitor_tx == MONITOR_EAPOL_DONE)
{
gRoamDelayMetaInfo.dxe_first_tx_time = vos_timer_get_system_time();
gRoamDelayMetaInfo.dxe_monitor_tx = MONITOR_STOP;
gRoamDelayMetaInfo.dxe_first_pkt_len = 75;
if(skb->len < gRoamDelayMetaInfo.dxe_first_pkt_len)
gRoamDelayMetaInfo.dxe_first_pkt_len = skb->len;
vos_mem_copy(&gRoamDelayMetaInfo.dxe_first_pkt_data, skb->data,
gRoamDelayMetaInfo.dxe_first_pkt_len);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"DXE %s XMIT first data frame after roaming", __func__);
}
}
}
break;
case e_SME_VO_ADDTS_REQ:
gRoamDelayMetaInfo.hdd_addts_vo_req_time = vos_timer_get_system_time();
break;
case e_SME_VO_ADDTS_RSP:
gRoamDelayMetaInfo.hdd_addts_vo_rsp_time = vos_timer_get_system_time();
break;
case e_SME_VI_ADDTS_REQ:
gRoamDelayMetaInfo.hdd_addts_vi_req_time = vos_timer_get_system_time();
break;
case e_SME_VI_ADDTS_RSP:
gRoamDelayMetaInfo.hdd_addts_vi_rsp_time = vos_timer_get_system_time();
break;
case e_CACHE_ROAM_DELAY_DATA:
//Let us copy roam meta info
if(gRoamDelayCurrentIndex > ROAM_DELAY_TABLE_SIZE)
gRoamDelayCurrentIndex = 0;
vos_mem_copy(&gpRoamDelayTable[gRoamDelayCurrentIndex++],
&gRoamDelayMetaInfo, sizeof(gRoamDelayMetaInfo));
vos_mem_set(&gRoamDelayMetaInfo, sizeof(gRoamDelayMetaInfo), 0);
break;
default:
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"%s Invalid roam_event = %d received ", __func__, roam_event);
break;
}
}
void vos_reset_roam_timer_log(void)
{
if (gpRoamDelayTable != NULL)
{
//Set zero to whole gpRoamDelayTable
vos_mem_set(gpRoamDelayTable, (sizeof(tRoamDelayMetaInfo) * ROAM_DELAY_TABLE_SIZE), 0);
}
}
void vos_dump_roam_time_log_service(void)
{
v_SLONG_t slA, slB, slC, slD, slE, slF, slG, slH, slI, slJ, slK, slL, slM, slRoamDelay;
tRoamDelayMetaInfo currentRoamDelayInfo;
v_ULONG_t index = 0,i=0;
if (gpRoamDelayTable == NULL)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"Roam delay table is not initialized\n");
return;
}
//Let us first copy the current gRoamDelayMetaInfo into gpRoamDelayTable
if(gRoamDelayCurrentIndex > ROAM_DELAY_TABLE_SIZE)
gRoamDelayCurrentIndex = 0;
vos_mem_copy(&gpRoamDelayTable[gRoamDelayCurrentIndex++], &gRoamDelayMetaInfo, sizeof(gRoamDelayMetaInfo));
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"** RoamDelay = ( dxe_first_tx_time - disable_tx_queues_time)\n");
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||========================"
"===============|====== A ======|====== B ======|====== C ======|"
"====== D ======|====== E ======|====== F ======|====== G ======|"
"====== H ======|====== I ======|====== J ======|====== K ======|"
"====== L ======|====== M ======||\n");
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||Sl | Peer MAC address |"
" **RoamDelay** | PreAuth Timer | Disassoc Issue| Add BSS Req |"
" AddBssRsp to | ReassocReq to | ReassocRsp to | Disable to |"
" M1-M2 DXE SW | M1-M2 HDD SW | M3-M4 DXE SW | M3-M4 HDD SW |"
" ReassocRsp to | HDD to DXE ||\n");
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||No.| |"
" ************* | to Roam Start | to Complete | to Rsp time |"
" Reassoc Req | ReassocRsp | Enable Tx Que | Enable Tx Que |"
" | | | |"
" Set GTK | 1st data frame||\n");
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||========================"
"================================================================"
"================================================================"
"================================================================"
"===============================||\n");
for (index = 0; index < gRoamDelayCurrentIndex; index++)
{
currentRoamDelayInfo = gpRoamDelayTable[index];
/* PreAuth Timer to Roam Start */
slA = (currentRoamDelayInfo.preauth_cb_time -
currentRoamDelayInfo.preauth_reassoc_start_time);
/* Disassoc Issue to Complete */
slB = (currentRoamDelayInfo.disassoc_comp_time -
currentRoamDelayInfo.disassoc_issue_time);
/* Add BSS Req to Rsp time */
slC = (currentRoamDelayInfo.lim_add_bss_rsp_time -
currentRoamDelayInfo.lim_add_bss_req_time);
/* AddBssRsp to Reassoc Req */
slD = (currentRoamDelayInfo.send_reassoc_req_time -
currentRoamDelayInfo.lim_add_bss_rsp_time);
/* ReassocReq to ReassocRsp */
slE = (currentRoamDelayInfo.hdd_sendassoc_rsp_time -
currentRoamDelayInfo.send_reassoc_req_time);
/* ReassocRsp to Enable Tx Que */
slF = (currentRoamDelayInfo.enable_tx_queues_reassoc_time -
currentRoamDelayInfo.hdd_sendassoc_rsp_time);
/* Disable to Enable Tx Que */
slG = (currentRoamDelayInfo.enable_tx_queues_reassoc_time -
currentRoamDelayInfo.disable_tx_queues_time);
/* M1-M2 DXE SW */
slH = (currentRoamDelayInfo.dxe_eapol_m2 -
currentRoamDelayInfo.dxe_eapol_m1);
/* M1-M2 HDD SW */
slI = (currentRoamDelayInfo.hdd_eapol_m2 -
currentRoamDelayInfo.hdd_eapol_m1);
/* M3-M4 DXE SW */
slJ = (currentRoamDelayInfo.dxe_eapol_m4 -
currentRoamDelayInfo.dxe_eapol_m3);
/* M3-M4 HDD SW */
slK = (currentRoamDelayInfo.hdd_eapol_m4 -
currentRoamDelayInfo.hdd_eapol_m3);
/* ReassocRsp to Set GTK */
slL = (currentRoamDelayInfo.set_gtk_roam_key_time -
currentRoamDelayInfo.hdd_sendassoc_rsp_time);
/* HDD to DXE 1st data frame */
slM = (currentRoamDelayInfo.dxe_first_tx_time -
currentRoamDelayInfo.hdd_first_xmit_time);
/* Calculate roam delay */
slRoamDelay = (currentRoamDelayInfo.dxe_first_tx_time -
currentRoamDelayInfo.disable_tx_queues_time);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||%2ld:|<"MAC_ADDRESS_STR">|"
"%14ld |%14ld |%14ld |%14ld |"
"%14ld |%14ld |%14ld |%14ld |"
"%14ld |%14ld |%14ld |%14ld |"
"%14ld |%14ld ||\n",
(index+1), MAC_ADDR_ARRAY(currentRoamDelayInfo.peer_mac_addr),
slRoamDelay, slA, slB, slC,
slD, slE, slF, slG,
slH, slI, slJ, slK,
slL, slM );
}
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||========================"
"================================================================"
"================================================================"
"================================================================"
"===============================||\n");
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||== More Details ====================="
"===============================||\n");
for (index = 0; index < gRoamDelayCurrentIndex; index++)
{
currentRoamDelayInfo = gpRoamDelayTable[index];
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||%2ld: Peer Mac: <"MAC_ADDRESS_STR">\n",
(index+1), MAC_ADDR_ARRAY(currentRoamDelayInfo.peer_mac_addr)
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||preauth_reassoc_start_time : %14ld\n",
currentRoamDelayInfo.preauth_reassoc_start_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||preauth_cb_time : %14ld\n",
currentRoamDelayInfo.preauth_cb_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||disable_tx_queues_time : %14ld\n",
currentRoamDelayInfo.disable_tx_queues_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||disassoc_issue_time : %14ld\n",
currentRoamDelayInfo.disassoc_issue_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||lim_add_bss_req_time : %14ld\n",
currentRoamDelayInfo.lim_add_bss_req_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||lim_add_bss_rsp_time : %14ld\n",
currentRoamDelayInfo.lim_add_bss_rsp_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||disassoc_comp_time : %14ld\n",
currentRoamDelayInfo.disassoc_comp_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||send_reassoc_req_time : %14ld\n",
currentRoamDelayInfo.send_reassoc_req_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||hdd_sendassoc_rsp_time : %14ld\n",
currentRoamDelayInfo.hdd_sendassoc_rsp_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||enable_tx_queues_time : %14ld\n",
currentRoamDelayInfo.enable_tx_queues_reassoc_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||hdd_eapol_m1 : %14ld\n",
currentRoamDelayInfo.hdd_eapol_m1
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||hdd_eapol_m2 : %14ld\n",
currentRoamDelayInfo.hdd_eapol_m2
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||hdd_eapol_m3 : %14ld\n",
currentRoamDelayInfo.hdd_eapol_m3
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||hdd_eapol_m4 : %14ld\n",
currentRoamDelayInfo.hdd_eapol_m4
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||dxe_eapol_m1 : %14ld\n",
currentRoamDelayInfo.dxe_eapol_m1
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||dxe_eapol_m2 : %14ld\n",
currentRoamDelayInfo.dxe_eapol_m2
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||dxe_eapol_m3 : %14ld\n",
currentRoamDelayInfo.dxe_eapol_m3
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||dxe_eapol_m4 : %14ld\n",
currentRoamDelayInfo.dxe_eapol_m4
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||set_ptk_roam_key_time : %14ld\n",
currentRoamDelayInfo.set_ptk_roam_key_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||set_gtk_roam_key_time : %14ld\n",
currentRoamDelayInfo.set_gtk_roam_key_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||tl_fetch_pkt_time : %14ld\n",
currentRoamDelayInfo.tl_fetch_pkt_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||hdd_first_xmit_time : %14ld\n",
currentRoamDelayInfo.hdd_first_xmit_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||dxe_first_tx_time : %14ld\n",
currentRoamDelayInfo.dxe_first_tx_time
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||hdd_first_pkt_data : \n"
);
for (i=0; i<currentRoamDelayInfo.hdd_first_pkt_len && i< (50-8); i+=8)
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||%2X, %2X, %2X, %2X, %2X, %2X, %2X, %2X, ",
currentRoamDelayInfo.hdd_first_pkt_data[i],
currentRoamDelayInfo.hdd_first_pkt_data[i+1],
currentRoamDelayInfo.hdd_first_pkt_data[i+2],
currentRoamDelayInfo.hdd_first_pkt_data[i+3],
currentRoamDelayInfo.hdd_first_pkt_data[i+4],
currentRoamDelayInfo.hdd_first_pkt_data[i+5],
currentRoamDelayInfo.hdd_first_pkt_data[i+6],
currentRoamDelayInfo.hdd_first_pkt_data[i+7]
);
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||dxe_first_pkt_data : \n"
);
for (i=0; i<currentRoamDelayInfo.dxe_first_pkt_len && i < (75-8); i+=8)
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||%2X, %2X, %2X, %2X, %2X, %2X, %2X, %2X, ",
currentRoamDelayInfo.dxe_first_pkt_data[i],
currentRoamDelayInfo.dxe_first_pkt_data[i+1],
currentRoamDelayInfo.dxe_first_pkt_data[i+2],
currentRoamDelayInfo.dxe_first_pkt_data[i+3],
currentRoamDelayInfo.dxe_first_pkt_data[i+4],
currentRoamDelayInfo.dxe_first_pkt_data[i+5],
currentRoamDelayInfo.dxe_first_pkt_data[i+6],
currentRoamDelayInfo.dxe_first_pkt_data[i+7]
);
}
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"||== END ====================="
"===============================||\n");
}
v_U32_t vos_copy_80211_data(void *pBuff, v_U8_t *dst, v_U8_t frametype)
{
vos_pkt_t *vos_pkt = NULL;
struct sk_buff *skb = NULL;
v_U32_t length_to_copy;
vos_pkt = (vos_pkt_t *)pBuff;
if(!vos_pkt || !dst)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"vos_pkt/dst is null");
return 0;
}
skb = vos_pkt->pSkb;
if(!skb)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
" skb is null");
return 0;
}
if (VOS_MAC_MGMT_FRAME == frametype)
{
length_to_copy = skb->len;
}
else
{
length_to_copy = VOS_DEF_PKT_STATS_LEN_TO_COPY;
if(skb->data[0] == VOS_QOS_DATA_VALUE)
length_to_copy += VOS_QOS_SIZE;
/* Copy whole skb data if DHCP or EAPOL pkt.Here length_to_copy
* will give the pointer to IP header and adding VOS_IP_HEADER_SIZE
* to it will give the DHCP port number.
*/
if (((skb->len > (length_to_copy + VOS_IP_HEADER_SIZE)) &&
((*((u16*)((u8*)skb->data + length_to_copy + VOS_IP_HEADER_SIZE))
== VOS_DHCP_SOURCE_PORT) ||
(*((u16*)((u8*)skb->data + length_to_copy + VOS_IP_HEADER_SIZE))
== VOS_DHCP_DESTINATION_PORT))) ||
vos_skb_is_eapol(skb,
VOS_ETHERTYPE_802_1_X_FRAME_OFFSET_IN_802_11_PKT,
VOS_ETHERTYPE_802_1_X_SIZE))
{
length_to_copy = skb->len;
}
}
if (length_to_copy > skb->len)
{
length_to_copy = skb->len;
}
if (length_to_copy > MAX_PKT_STAT_DATA_LEN)
{
length_to_copy = MAX_PKT_STAT_DATA_LEN;
}
vos_mem_copy(dst, skb->data, length_to_copy);
return length_to_copy;
}
#ifdef FEATURE_WLAN_DIAG_SUPPORT
/**
* vos_tdls_tx_rx_mgmt_event()- send tdls mgmt rx tx event
*
* @event_id: event id
* @tx_rx: tx or rx
* @type: type of frame
* @action_sub_type: action frame type
* @peer_mac: peer mac
*
* This Function sendsend tdls mgmt rx tx diag event
*
* Return: void.
*/
void vos_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx,
uint8_t type, uint8_t action_sub_type, uint8_t *peer_mac)
{
WLAN_VOS_DIAG_EVENT_DEF(tdls_tx_rx_mgmt,
struct vos_event_tx_rx_mgmt);
vos_mem_zero(&tdls_tx_rx_mgmt, sizeof(tdls_tx_rx_mgmt));
tdls_tx_rx_mgmt.event_id = event_id;
tdls_tx_rx_mgmt.tx_rx = tx_rx;
tdls_tx_rx_mgmt.type = type;
tdls_tx_rx_mgmt.action_sub_type = action_sub_type;
vos_mem_copy(tdls_tx_rx_mgmt.peer_mac,
peer_mac, VOS_MAC_ADDR_SIZE);
WLAN_VOS_DIAG_EVENT_REPORT(&tdls_tx_rx_mgmt,
EVENT_WLAN_TX_RX_MGMT);
}
#endif