blob: fbfb9b41b3120cef2dedddc142b910e979afee3f [file] [log] [blame]
/*
* Copyright (c) 2011-2017 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/err.h>
#include <linux/random.h>
#if(LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0))
#include <crypto/skcipher.h>
#else
#include <linux/crypto.h>
#endif
#include <linux/scatterlist.h>
#include <linux/completion.h>
#include <linux/ieee80211.h>
#include <crypto/hash.h>
#include <crypto/aes.h>
#include <wcnss_api.h>
#ifdef CONFIG_CNSS
#include <linux/qcomwlan_secif.h>
#endif
#include <errno.h>
#include "ieee80211_common.h"
/*----------------------------------------------------------------------------
* Preprocessor Definitions and Constants
* -------------------------------------------------------------------------*/
#define AAD_LEN 20
#define IV_SIZE_AES_128 16
#define CMAC_IPN_LEN 6
/*----------------------------------------------------------------------------
* Type Declarations
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Global Data Definitions
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Static Variable Definitions
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
Function Definitions and Documentation
* -------------------------------------------------------------------------*/
#ifndef CONFIG_CNSS
#if defined(WLAN_FEATURE_11W) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */
static inline void xor_128(const u8 *a, const u8 *b, u8 *out)
{
u8 i;
for (i = 0; i < AES_BLOCK_SIZE; i++)
out[i] = a[i] ^ b[i];
}
static inline void leftshift_onebit(const u8 *input, u8 *output)
{
int i, overflow = 0;
for (i = (AES_BLOCK_SIZE - 1); i >= 0; i--) {
output[i] = input[i] << 1;
output[i] |= overflow;
overflow = (input[i] & 0x80) ? 1 : 0;
}
return;
}
static void generate_subkey(struct crypto_cipher *tfm, u8 *k1, u8 *k2)
{
u8 l[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
u8 const_rb[AES_BLOCK_SIZE] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87};
u8 const_zero[AES_BLOCK_SIZE] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
crypto_cipher_encrypt_one(tfm, l, const_zero);
if ((l[0] & 0x80) == 0) { /* If MSB(l) = 0, then k1 = l << 1 */
leftshift_onebit(l, k1);
} else { /* Else k1 = ( l << 1 ) (+) Rb */
leftshift_onebit(l, tmp);
xor_128(tmp, const_rb, k1);
}
if ((k1[0] & 0x80) == 0) {
leftshift_onebit(k1, k2);
} else {
leftshift_onebit(k1, tmp);
xor_128(tmp, const_rb, k2);
}
}
static inline void padding(u8 *lastb, u8 *pad, u16 length)
{
u8 j;
/* original last block */
for (j = 0; j < AES_BLOCK_SIZE; j++) {
if (j < length)
pad[j] = lastb[j];
else if (j == length)
pad[j] = 0x80;
else
pad[j] = 0x00;
}
}
void cmac_calc_mic(struct crypto_cipher *tfm, u8 *m,
u16 length, u8 *mac)
{
u8 x[AES_BLOCK_SIZE], y[AES_BLOCK_SIZE];
u8 m_last[AES_BLOCK_SIZE], padded[AES_BLOCK_SIZE];
u8 k1[AES_KEYSIZE_128], k2[AES_KEYSIZE_128];
int cmpBlk;
int i, nBlocks = (length + 15)/AES_BLOCK_SIZE;
generate_subkey(tfm, k1, k2);
if (nBlocks == 0) {
nBlocks = 1;
cmpBlk = 0;
} else {
cmpBlk = ((length % AES_BLOCK_SIZE) == 0) ? 1 : 0;
}
if (cmpBlk) { /* Last block is complete block */
xor_128(&m[AES_BLOCK_SIZE * (nBlocks - 1)], k1, m_last);
} else { /* Last block is not complete block */
padding(&m[AES_BLOCK_SIZE * (nBlocks - 1)], padded,
length % AES_BLOCK_SIZE);
xor_128(padded, k2, m_last);
}
for (i = 0; i < AES_BLOCK_SIZE; i++)
x[i] = 0;
for (i = 0; i < (nBlocks - 1); i++) {
xor_128(x, &m[AES_BLOCK_SIZE * i], y); /* y = Mi (+) x */
crypto_cipher_encrypt_one(tfm, x, y); /* x = AES-128(KEY, y) */
}
xor_128(x, m_last, y);
crypto_cipher_encrypt_one(tfm, x, y);
vos_mem_copy(mac, x, CMAC_TLEN);
}
#endif
#endif
/*--------------------------------------------------------------------------
\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 );
}
/*--------------------------------------------------------------------------
\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;
//check for invalid pointer
if ( NULL == pbBuf )
{
uResult = VOS_STATUS_E_FAULT;
return ( uResult );
}
get_random_bytes( pbBuf, numBytes);
// "Random sequence generated."
uResult = VOS_STATUS_SUCCESS;
return ( uResult );
}
#ifdef WLAN_FEATURE_11W
v_U8_t vos_get_mmie_size()
{
return sizeof(struct ieee80211_mmie);
}
/*--------------------------------------------------------------------------
\brief vos_increase_seq() - Increase the IPN aka Sequence number by one unit
The vos_increase_seq() function increases the IPN by one unit.
\param ipn - pointer to the IPN aka Sequence number [6 bytes]
--------------------------------------------------------------------------*/
static void
vos_increase_seq(v_U8_t *ipn)
{
v_U64_t value = 0;
if (ipn)
{
value = (0xffffffffffff)& (*((v_U64_t *)ipn));
value = value + 1;
vos_mem_copy(ipn, &value, IEEE80211_MMIE_IPNLEN);
}
}
/*--------------------------------------------------------------------------
\brief vos_attach_mmie() - attches the complete MMIE at the end of frame
The vos_attach_mmie() calculates the entire MMIE and attaches at the end
of Broadcast/Multicast robust management frames.
\param igtk - pointer group key which will be used to calculate
the 8 byte MIC.
\param ipn - pointer ipn, it is also known as sequence number
\param key_id - key identication number
\param frm - pointer to the start of the frame.
\param efrm - pointer to the end of the frame.
\param frmLen - size of the entire frame.
\return - this function will return VOS_TRUE on success and VOS_FALSE on
failure.
--------------------------------------------------------------------------*/
v_BOOL_t
vos_attach_mmie(v_U8_t *igtk, v_U8_t *ipn, u_int16_t key_id,
v_U8_t* frm, v_U8_t* efrm, u_int16_t frmLen)
{
struct ieee80211_mmie *mmie;
struct ieee80211_frame *wh;
v_U8_t aad[AAD_LEN], mic[CMAC_TLEN], *input = NULL;
v_U8_t previous_ipn[IEEE80211_MMIE_IPNLEN] = {0};
v_U16_t nBytes = 0;
int ret = 0;
struct crypto_cipher *tfm;
/* This is how received frame look like
*
* <------------frmLen---------------------------->
*
* +---------------+----------------------+-------+
* | 802.11 HEADER | Management framebody | MMIE |
* +---------------+----------------------+-------+
* ^
* |
* efrm
* This is how MMIE from above frame look like
*
*
* <------------ 18 Bytes----------------------------->
* +--------+---------+---------+-----------+---------+
* |Element | Length | Key id | IPN | MIC |
* | id | | | | |
* +--------+---------+---------+-----------+---------+
* Octet 1 1 2 6 8
*
*/
/* Check if frame is invalid length */
if (((efrm - frm) != frmLen) || (frmLen < sizeof(*wh)))
{
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
"%s: Invalid frame length", __func__);
return VOS_FALSE;
}
mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie));
/* Copy Element id */
mmie->element_id = IEEE80211_ELEMID_MMIE;
/* Copy Length */
mmie->length = sizeof(*mmie)-2;
/* Copy Key id */
mmie->key_id = key_id;
/*
* In case of error, revert back to original IPN
* to do that copy the original IPN into previous_ipn
*/
vos_mem_copy(&previous_ipn[0], ipn, IEEE80211_MMIE_IPNLEN);
vos_increase_seq(ipn);
vos_mem_copy(mmie->sequence_number, ipn, IEEE80211_MMIE_IPNLEN);
/*
* Calculate MIC and then copy
*/
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
tfm = crypto_alloc_cipher( "aes", 0, CRYPTO_ALG_ASYNC);
#else
tfm = wcnss_wlan_crypto_alloc_cipher( "aes", 0, CRYPTO_ALG_ASYNC);
#endif
if (IS_ERR(tfm))
{
ret = PTR_ERR(tfm);
tfm = NULL;
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,
"%s: crypto_alloc_cipher failed (%d)", __func__, ret);
goto err_tfm;
}
ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128);
if (ret) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,
"%s: crypto_cipher_setkey failed (%d)", __func__, ret);
goto err_tfm;
}
/* Construct AAD */
wh = (struct ieee80211_frame *)frm;
/* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */
/* FC type/subtype */
aad[0] = wh->i_fc[0];
/* Mask FC Retry, PwrMgt, MoreData flags to zero */
aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT |
IEEE80211_FC1_MORE_DATA);
/* A1 || A2 || A3 */
vos_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN);
/* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */
nBytes = AAD_LEN + (frmLen - sizeof(struct ieee80211_frame));
input = (v_U8_t *)vos_mem_malloc(nBytes);
if (NULL == input)
{
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
"%s: Memory allocation failed", __func__);
ret = VOS_STATUS_E_NOMEM;
goto err_tfm;
}
/*
* Copy the AAD, Management frame body, and
* MMIE with 8 bit MIC zeroed out
*/
vos_mem_zero(input, nBytes);
vos_mem_copy(input, aad, AAD_LEN);
/* Copy Management Frame Body and MMIE without MIC*/
vos_mem_copy(input+AAD_LEN,
(v_U8_t*)(efrm-(frmLen-sizeof(struct ieee80211_frame))),
nBytes - AAD_LEN - CMAC_TLEN);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
cmac_calc_mic(tfm, input, nBytes, mic);
#else
wcnss_wlan_cmac_calc_mic(tfm, input, nBytes, mic);
#endif
vos_mem_free(input);
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
"CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X",
mic[0], mic[1], mic[2], mic[3],
mic[4], mic[5], mic[6], mic[7]);
vos_mem_copy(mmie->mic, mic, IEEE80211_MMIE_MICLEN);
err_tfm:
if (ret)
{
vos_mem_copy(ipn, previous_ipn, IEEE80211_MMIE_IPNLEN);
}
if (tfm)
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
crypto_free_cipher(tfm);
#else
wcnss_wlan_crypto_free_cipher(tfm);
#endif
return !ret?VOS_TRUE:VOS_FALSE;
}
v_BOOL_t vos_is_mmie_valid(v_U8_t *igtk, v_U8_t *ipn,
v_U8_t* frm, v_U8_t* efrm)
{
struct ieee80211_mmie *mmie;
struct ieee80211_frame *wh;
v_U8_t *rx_ipn, aad[AAD_LEN], mic[CMAC_TLEN], *input;
v_U16_t nBytes = 0;
int ret = 0;
struct crypto_cipher *tfm;
/* Check if frame is invalid length */
if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
"Invalid frame length");
return VOS_FALSE;
}
mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie));
/* Check Element ID */
if ((mmie->element_id != IEEE80211_ELEMID_MMIE) ||
(mmie->length != (sizeof(*mmie)-2))) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
"IE is not Mgmt MIC IE or Invalid length");
/* IE is not Mgmt MIC IE or invalid length */
return VOS_FALSE;
}
/* Validate IPN */
rx_ipn = mmie->sequence_number;
if (OS_MEMCMP(rx_ipn, ipn, CMAC_IPN_LEN) <= 0)
{
/* Replay error */
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
"Replay error mmie ipn %02X %02X %02X %02X %02X %02X"
" drvr ipn %02X %02X %02X %02X %02X %02X",
rx_ipn[0], rx_ipn[1], rx_ipn[2], rx_ipn[3], rx_ipn[4], rx_ipn[5],
ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], ipn[5]);
return VOS_FALSE;
}
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
tfm = crypto_alloc_cipher( "aes", 0, CRYPTO_ALG_ASYNC);
#else
tfm = wcnss_wlan_crypto_alloc_cipher( "aes", 0, CRYPTO_ALG_ASYNC);
#endif
if (IS_ERR(tfm)) {
ret = PTR_ERR(tfm);
tfm = NULL;
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,
"crypto_alloc_cipher failed (%d)", ret);
goto err_tfm;
}
ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128);
if (ret) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,
"crypto_cipher_setkey failed (%d)", ret);
goto err_tfm;
}
/* Construct AAD */
wh = (struct ieee80211_frame *)frm;
/* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */
/* FC type/subtype */
aad[0] = wh->i_fc[0];
/* Mask FC Retry, PwrMgt, MoreData flags to zero */
aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT |
IEEE80211_FC1_MORE_DATA);
/* A1 || A2 || A3 */
vos_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN);
/* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */
nBytes = AAD_LEN + (efrm - (v_U8_t*)(wh+1));
input = (v_U8_t *)vos_mem_malloc(nBytes);
if (NULL == input)
{
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
"Memory allocation failed");
ret = VOS_STATUS_E_NOMEM;
goto err_tfm;
}
/* Copy the AAD, MMIE with 8 bit MIC zeroed out */
vos_mem_zero(input, nBytes);
vos_mem_copy(input, aad, AAD_LEN);
vos_mem_copy(input+AAD_LEN, (v_U8_t*)(wh+1), nBytes - AAD_LEN - CMAC_TLEN);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
cmac_calc_mic(tfm, input, nBytes, mic);
#else
wcnss_wlan_cmac_calc_mic(tfm, input, nBytes, mic);
#endif
vos_mem_free(input);
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
"CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X",
mic[0], mic[1], mic[2], mic[3],
mic[4], mic[5], mic[6], mic[7]);
if (OS_MEMCMP(mic, mmie->mic, CMAC_TLEN) != 0) {
/* MMIE MIC mismatch */
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
"BC/MC MGMT frame MMIE MIC check Failed"
" rmic %02X %02X %02X %02X %02X %02X %02X %02X"
" cmic %02X %02X %02X %02X %02X %02X %02X %02X",
mmie->mic[0], mmie->mic[1], mmie->mic[2], mmie->mic[3],
mmie->mic[4], mmie->mic[5], mmie->mic[6], mmie->mic[7],
mic[0], mic[1], mic[2], mic[3],
mic[4], mic[5], mic[6], mic[7]);
return VOS_FALSE;
}
/* Update IPN */
vos_mem_copy(ipn, rx_ipn, CMAC_IPN_LEN);
err_tfm:
if (tfm)
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
crypto_free_cipher(tfm);
#else
wcnss_wlan_crypto_free_cipher(tfm);
#endif
return !ret?VOS_TRUE:VOS_FALSE;
}
#endif /* WLAN_FEATURE_11W */
/**
* 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);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
tfm = crypto_alloc_ahash("hmac(sha1)", CRYPTO_ALG_TYPE_AHASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
#else
tfm = wcnss_wlan_crypto_alloc_ahash("hmac(sha1)", CRYPTO_ALG_TYPE_AHASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
#endif
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);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
ret = crypto_ahash_setkey(tfm, key, ksize);
#else
ret = wcnss_wlan_crypto_ahash_setkey(tfm, key, ksize);
#endif
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);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
ret = crypto_ahash_digest(req);
#else
ret = wcnss_wlan_crypto_ahash_digest(req);
#endif
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:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
crypto_free_ahash(tfm);
#else
wcnss_wlan_crypto_free_ahash(tfm);
#endif
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);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
tfm = crypto_alloc_ahash("hmac(md5)", CRYPTO_ALG_TYPE_AHASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
#else
tfm = wcnss_wlan_crypto_alloc_ahash("hmac(md5)", CRYPTO_ALG_TYPE_AHASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
#endif
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);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
ret = crypto_ahash_setkey(tfm, key, ksize);
#else
ret = wcnss_wlan_crypto_ahash_setkey(tfm, key, ksize);
#endif
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);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
ret = crypto_ahash_digest(req);
#else
ret = wcnss_wlan_crypto_ahash_digest(req);
#endif
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:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
crypto_free_ahash(tfm);
#else
wcnss_wlan_crypto_free_ahash(tfm);
#endif
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);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0))
/*--------------------------------------------------------------------------
\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 )
--------------------------------------------------------------------------*/
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 */
{
struct ecb_aes_result result;
struct crypto_skcipher *tfm;
struct skcipher_request *req;
int ret = 0;
char iv[IV_SIZE_AES_128];
struct scatterlist sg_in;
struct scatterlist sg_out;
init_completion(&result.completion);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
tfm = crypto_alloc_skcipher( "cbc(aes)", 0, 0);
#else
tfm = wcnss_wlan_crypto_alloc_ablkcipher( "cbc(aes)", 0, 0);
#endif
if (IS_ERR(tfm)) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_alloc_skcipher failed");
ret = PTR_ERR(tfm);
goto err_tfm;
}
req = skcipher_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;
}
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
ecb_aes_complete, &result);
crypto_skcipher_clear_flags(tfm, ~0);
ret = crypto_skcipher_setkey(tfm, pKey, AES_KEYSIZE_128);
if (ret) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_skcipher_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);
skcipher_request_set_crypt(req, &sg_in, &sg_out, AES_BLOCK_SIZE, iv);
ret = crypto_skcipher_encrypt(req);
if (ret == -EINPROGRESS || ret == -EBUSY) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_skcipher_encrypt failed ret %d", ret);
wait_for_completion(&result.completion);
ret = result.err;
}
// -------------------------------------
err_setkey:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
skcipher_request_free(req);
#else
wcnss_wlan_ablkcipher_request_free(req);
#endif
err_req:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
crypto_free_skcipher(tfm);
#else
wcnss_wlan_crypto_free_ablkcipher(tfm);
#endif
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;
}
#else //(LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0))
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 */
{
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);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
tfm = crypto_alloc_ablkcipher( "cbc(aes)", 0, 0);
#else
tfm = wcnss_wlan_crypto_alloc_ablkcipher( "cbc(aes)", 0, 0);
#endif
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, AES_KEYSIZE_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:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
ablkcipher_request_free(req);
#else
wcnss_wlan_ablkcipher_request_free(req);
#endif
err_req:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
crypto_free_ablkcipher(tfm);
#else
wcnss_wlan_crypto_free_ablkcipher(tfm);
#endif
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 //(LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0))
/*--------------------------------------------------------------------------
\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 skcipher_request *req;
struct crypto_skcipher *tfm;
int ret = 0;
char iv[IV_SIZE_AES_128];
struct scatterlist sg_in;
struct scatterlist sg_out;
init_completion(&result.completion);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
tfm = crypto_alloc_skcipher( "cbc(aes)", 0, 0);
#else
tfm = wcnss_wlan_crypto_alloc_ablkcipher( "cbc(aes)", 0, 0);
#endif
if (IS_ERR(tfm)) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_alloc_skcipher failed");
ret = PTR_ERR(tfm);
goto err_tfm;
}
req = skcipher_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;
}
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
ecb_aes_complete, &result);
crypto_skcipher_clear_flags(tfm, ~0);
ret = crypto_skcipher_setkey(tfm, pKey, AES_KEYSIZE_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);
skcipher_request_set_crypt(req, &sg_in, &sg_out, AES_BLOCK_SIZE, iv);
ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
if (ret) {
VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR,"AES: failed to decrypt received packet");
}
// -------------------------------------
err_setkey:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
skcipher_request_free(req);
#else
wcnss_wlan_ablkcipher_request_free(req);
#endif
err_req:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
crypto_free_skcipher(tfm);
#else
wcnss_wlan_crypto_free_ablkcipher(tfm);
#endif
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;
}
#else //LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0)
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);
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
tfm = crypto_alloc_ablkcipher( "cbc(aes)", 0, 0);
#else
tfm = wcnss_wlan_crypto_alloc_ablkcipher( "cbc(aes)", 0, 0);
#endif
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, AES_KEYSIZE_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:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
ablkcipher_request_free(req);
#else
wcnss_wlan_ablkcipher_request_free(req);
#endif
err_req:
#if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO) || defined(CONFIG_NON_QC_PLATFORM_PCI))
crypto_free_ablkcipher(tfm);
#else
wcnss_wlan_crypto_free_ablkcipher(tfm);
#endif
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 //(LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0))
v_U32_t vos_chan_to_freq(v_U8_t chan)
{
if (chan < VOS_24_GHZ_CHANNEL_14) // ch 0 - ch 13
return VOS_24_GHZ_BASE_FREQ + chan * VOS_CHAN_SPACING_5MHZ;
else if (chan == VOS_24_GHZ_CHANNEL_14) // ch 14
return VOS_CHAN_14_FREQ;
else if (chan < VOS_24_GHZ_CHANNEL_27) // ch 15 - ch 26
return VOS_CHAN_15_FREQ +
(chan - VOS_24_GHZ_CHANNEL_15) * VOS_CHAN_SPACING_20MHZ;
else if (chan == VOS_5_GHZ_CHANNEL_170)
return VOS_CHAN_170_FREQ;
else
return VOS_5_GHZ_BASE_FREQ + chan * VOS_CHAN_SPACING_5MHZ;
}
v_U8_t vos_freq_to_chan(v_U32_t freq)
{
v_U8_t chan;
if (freq > VOS_24_GHZ_BASE_FREQ && freq < VOS_CHAN_14_FREQ)
chan = ((freq - VOS_24_GHZ_BASE_FREQ)/VOS_CHAN_SPACING_5MHZ);
else if (freq == VOS_CHAN_14_FREQ)
chan = VOS_24_GHZ_CHANNEL_14;
else if ((freq > VOS_24_GHZ_BASE_FREQ) && (freq < VOS_5_GHZ_BASE_FREQ))
chan = (((freq - VOS_CHAN_15_FREQ)/VOS_CHAN_SPACING_20MHZ) +
VOS_24_GHZ_CHANNEL_15);
else
chan = (freq - VOS_5_GHZ_BASE_FREQ)/VOS_CHAN_SPACING_5MHZ;
return chan;
}
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;
}
#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 sends 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_tdls_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_TDLS_TX_RX_MGMT);
}
#endif
/**
* vos_rounddown_pow_of_two() - Round down to nearest power of two
* @n: number to be tested
*
* Test if the input number is power of two, and return the nearest power of two
*
* Return: number rounded down to the nearest power of two
*/
unsigned long vos_rounddown_pow_of_two(unsigned long n)
{
if (is_power_of_2(n))
return n; /* already a power of 2 */
return __rounddown_pow_of_two(n);
}
/**
* vos_status_to_os_return(): translates vos_status types to linux return types
* @status: status to translate
*
* Translates error types that linux may want to handle specially.
*
* return: 0 or the linux error code that most closely matches the VOS_STATUS.
* defaults to -1 (EPERM)
*/
int vos_status_to_os_return(VOS_STATUS status)
{
switch (status) {
case VOS_STATUS_SUCCESS:
return 0;
case VOS_STATUS_E_FAULT:
return -EFAULT;
case VOS_STATUS_E_TIMEOUT:
case VOS_STATUS_E_BUSY:
return -EBUSY;
case VOS_STATUS_E_AGAIN:
return -EAGAIN;
case VOS_STATUS_E_NOSUPPORT:
return -ENOSYS;
case VOS_STATUS_E_ALREADY:
return -EALREADY;
case VOS_STATUS_E_NOMEM:
return -ENOMEM;
case VOS_STATUS_E_FAILURE:
case VOS_STATUS_E_INVAL:
return -EINVAL;
default:
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
FL("Unhandled VOS_STATUS:%d"), status);
return -EPERM;
}
}