qcacld-3.0: Use crypto API to fill and validate mmie
Use crypto API to fill and validate mmie for BC frames. Change-Id: Ibe420f974c1f8fb3796168e6db976061f904d520 CRs-Fixed: 2664276
This commit is contained in:
parent
405d82a9cb
commit
3f29b6c7f2
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if !defined(__CDS_CRYPTO_H)
|
||||
#define __CDS_CRYPTO_H
|
||||
|
||||
/**
|
||||
* DOC: cds_crypto.h
|
||||
*
|
||||
* Crypto APIs
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/crypto.h>
|
||||
|
||||
static inline struct crypto_cipher *
|
||||
cds_crypto_alloc_cipher(const char *alg_name, u32 type, u32 mask)
|
||||
{
|
||||
return crypto_alloc_cipher(alg_name, type, mask);
|
||||
}
|
||||
|
||||
static inline void cds_crypto_free_cipher(struct crypto_cipher *tfm)
|
||||
{
|
||||
crypto_free_cipher(tfm);
|
||||
}
|
||||
|
||||
#endif /* if !defined __CDS_CRYPTO_H */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
@ -101,23 +101,7 @@ uint8_t cds_freq_to_chan(uint32_t freq);
|
||||
enum cds_band_type cds_chan_to_band(uint32_t chan);
|
||||
|
||||
#ifdef WLAN_FEATURE_11W
|
||||
bool cds_is_mmie_valid(uint8_t *key, uint8_t *ipn,
|
||||
uint8_t *frm, uint8_t *efrm);
|
||||
bool cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id,
|
||||
uint8_t *frm, uint8_t *efrm, uint16_t frmLen);
|
||||
uint8_t cds_get_mmie_size(void);
|
||||
/**
|
||||
* cds_is_gmac_mmie_valid: Validates GMAC MIC
|
||||
* @igtk: integrity group temporal key
|
||||
* @ipn: IGTK packet number
|
||||
* @frm: IEEE 802.11 frame
|
||||
* @efrm: End of frame
|
||||
* @key_length: Length of IGTK
|
||||
*
|
||||
* Return: True if MIC validation is successful, false otherwise
|
||||
*/
|
||||
bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm,
|
||||
uint8_t *efrm, uint16_t key_length);
|
||||
|
||||
/**
|
||||
* cds_get_gmac_mmie_size: Gives length of GMAC MMIE size
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
@ -40,8 +40,6 @@
|
||||
#include "qdf_trace.h"
|
||||
#include "cds_utils.h"
|
||||
#include "qdf_mem.h"
|
||||
#include "cds_crypto.h"
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/crypto.h>
|
||||
@ -57,10 +55,6 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
* Preprocessor Definitions and Constants
|
||||
* -------------------------------------------------------------------------*/
|
||||
#define AAD_LEN 20
|
||||
#define CMAC_IPN_LEN 6
|
||||
#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */
|
||||
#define GMAC_NONCE_LEN 12
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Type Declarations
|
||||
@ -75,111 +69,6 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
Function Definitions and Documentation
|
||||
* -------------------------------------------------------------------------*/
|
||||
#ifdef WLAN_FEATURE_11W
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void cds_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);
|
||||
|
||||
memcpy(mac, x, CMAC_TLEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WLAN_FEATURE_11W
|
||||
uint8_t cds_get_mmie_size(void)
|
||||
@ -187,279 +76,6 @@ uint8_t cds_get_mmie_size(void)
|
||||
return sizeof(struct ieee80211_mmie);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
\brief cds_increase_seq() - Increase the IPN aka Sequence number by one unit
|
||||
|
||||
The cds_increase_seq() function increases the IPN by one unit.
|
||||
|
||||
\param ipn - pointer to the IPN aka Sequence number [6 bytes]
|
||||
|
||||
--------------------------------------------------------------------------*/
|
||||
static void cds_increase_seq(uint8_t *ipn)
|
||||
{
|
||||
uint64_t value = 0;
|
||||
|
||||
if (ipn) {
|
||||
value = (0xffffffffffff) & (*((uint64_t *) ipn));
|
||||
value = value + 1;
|
||||
qdf_mem_copy(ipn, &value, IEEE80211_MMIE_IPNLEN);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
\brief cds_attach_mmie() - attches the complete MMIE at the end of frame
|
||||
|
||||
The cds_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 true on success and false on
|
||||
failure.
|
||||
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
bool
|
||||
cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id,
|
||||
uint8_t *frm, uint8_t *efrm, uint16_t frmLen)
|
||||
{
|
||||
struct ieee80211_mmie *mmie;
|
||||
struct ieee80211_frame *wh;
|
||||
uint8_t aad[AAD_LEN], mic[CMAC_TLEN], *input = NULL;
|
||||
uint8_t previous_ipn[IEEE80211_MMIE_IPNLEN] = { 0 };
|
||||
uint16_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))) {
|
||||
cds_err("Invalid frame length");
|
||||
return false;
|
||||
}
|
||||
mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie));
|
||||
|
||||
/* Copy Element id */
|
||||
mmie->element_id = WLAN_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
|
||||
*/
|
||||
qdf_mem_copy(&previous_ipn[0], ipn, IEEE80211_MMIE_IPNLEN);
|
||||
cds_increase_seq(ipn);
|
||||
qdf_mem_copy(mmie->sequence_number, ipn, IEEE80211_MMIE_IPNLEN);
|
||||
|
||||
/*
|
||||
* Calculate MIC and then copy
|
||||
*/
|
||||
tfm = cds_crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm)) {
|
||||
ret = PTR_ERR(tfm);
|
||||
tfm = NULL;
|
||||
cds_err("crypto_alloc_cipher failed (%d)", ret);
|
||||
goto err_tfm;
|
||||
}
|
||||
|
||||
ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128);
|
||||
if (ret) {
|
||||
cds_err("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 */
|
||||
qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * QDF_MAC_ADDR_SIZE);
|
||||
|
||||
/* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */
|
||||
nBytes = AAD_LEN + (frmLen - sizeof(struct ieee80211_frame));
|
||||
input = (uint8_t *) qdf_mem_malloc(nBytes);
|
||||
if (!input) {
|
||||
cds_err("Memory allocation failed");
|
||||
ret = QDF_STATUS_E_NOMEM;
|
||||
goto err_tfm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the AAD, Management frame body, and
|
||||
* MMIE with 8 bit MIC zeroed out
|
||||
*/
|
||||
qdf_mem_copy(input, aad, AAD_LEN);
|
||||
/* Copy Management Frame Body and MMIE without MIC */
|
||||
qdf_mem_copy(input + AAD_LEN,
|
||||
(uint8_t *) (efrm -
|
||||
(frmLen - sizeof(struct ieee80211_frame))),
|
||||
nBytes - AAD_LEN - CMAC_TLEN);
|
||||
|
||||
cds_cmac_calc_mic(tfm, input, nBytes, mic);
|
||||
qdf_mem_free(input);
|
||||
|
||||
cds_debug("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]);
|
||||
qdf_mem_copy(mmie->mic, mic, IEEE80211_MMIE_MICLEN);
|
||||
|
||||
err_tfm:
|
||||
if (ret) {
|
||||
qdf_mem_copy(ipn, previous_ipn, IEEE80211_MMIE_IPNLEN);
|
||||
}
|
||||
|
||||
if (tfm)
|
||||
cds_crypto_free_cipher(tfm);
|
||||
return !ret ? true : false;
|
||||
}
|
||||
|
||||
bool
|
||||
cds_is_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, uint8_t *efrm)
|
||||
{
|
||||
struct ieee80211_mmie *mmie;
|
||||
struct ieee80211_frame *wh;
|
||||
uint8_t *rx_ipn, aad[AAD_LEN], mic[CMAC_TLEN], *input;
|
||||
uint16_t nBytes = 0;
|
||||
int ret = 0;
|
||||
struct crypto_cipher *tfm;
|
||||
|
||||
/* Check if frame is invalid length */
|
||||
if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) {
|
||||
cds_err("Invalid frame length");
|
||||
return false;
|
||||
}
|
||||
|
||||
mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie));
|
||||
|
||||
/* Check Element ID */
|
||||
if ((mmie->element_id != WLAN_ELEMID_MMIE) ||
|
||||
(mmie->length != (sizeof(*mmie) - 2))) {
|
||||
cds_err("IE is not Mgmt MIC IE or Invalid length");
|
||||
/* IE is not Mgmt MIC IE or invalid length */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Validate IPN */
|
||||
rx_ipn = mmie->sequence_number;
|
||||
if (qdf_mem_cmp(rx_ipn, ipn, CMAC_IPN_LEN) <= 0) {
|
||||
/* Replay error */
|
||||
cds_err("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 false;
|
||||
}
|
||||
tfm = cds_crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm)) {
|
||||
ret = PTR_ERR(tfm);
|
||||
tfm = NULL;
|
||||
cds_err("crypto_alloc_cipher failed (%d)", ret);
|
||||
goto err_tfm;
|
||||
}
|
||||
|
||||
ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128);
|
||||
if (ret) {
|
||||
cds_err("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 */
|
||||
qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * QDF_MAC_ADDR_SIZE);
|
||||
|
||||
/* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */
|
||||
nBytes = AAD_LEN + (efrm - (uint8_t *) (wh + 1));
|
||||
input = (uint8_t *) qdf_mem_malloc(nBytes);
|
||||
if (!input) {
|
||||
cds_err("Memory allocation failed");
|
||||
ret = QDF_STATUS_E_NOMEM;
|
||||
goto err_tfm;
|
||||
}
|
||||
|
||||
/* Copy the AAD, MMIE with 8 bit MIC zeroed out */
|
||||
qdf_mem_copy(input, aad, AAD_LEN);
|
||||
qdf_mem_copy(input + AAD_LEN, (uint8_t *) (wh + 1),
|
||||
nBytes - AAD_LEN - CMAC_TLEN);
|
||||
|
||||
cds_cmac_calc_mic(tfm, input, nBytes, mic);
|
||||
qdf_mem_free(input);
|
||||
|
||||
cds_err("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 (qdf_mem_cmp(mic, mmie->mic, CMAC_TLEN) != 0) {
|
||||
/* MMIE MIC mismatch */
|
||||
cds_err("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 false;
|
||||
}
|
||||
|
||||
/* Update IPN */
|
||||
qdf_mem_copy(ipn, rx_ipn, CMAC_IPN_LEN);
|
||||
|
||||
err_tfm:
|
||||
if (tfm)
|
||||
cds_crypto_free_cipher(tfm);
|
||||
|
||||
return !ret ? true : false;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
|
||||
uint8_t cds_get_gmac_mmie_size(void)
|
||||
{
|
||||
@ -472,119 +88,6 @@ uint8_t cds_get_gmac_mmie_size(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ipn_swap: Swaps ipn
|
||||
* @d: destination pointer
|
||||
* @s: source pointer
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static inline void ipn_swap(u8 *d, const u8 *s)
|
||||
{
|
||||
*d++ = s[5];
|
||||
*d++ = s[4];
|
||||
*d++ = s[3];
|
||||
*d++ = s[2];
|
||||
*d++ = s[1];
|
||||
*d = s[0];
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
|
||||
bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm,
|
||||
uint8_t *efrm, uint16_t key_length)
|
||||
{
|
||||
struct ieee80211_mmie_16 *mmie;
|
||||
struct ieee80211_frame *wh;
|
||||
uint8_t rx_ipn[6], aad[AAD_LEN];
|
||||
uint8_t mic[IEEE80211_MMIE_GMAC_MICLEN] = {0};
|
||||
uint16_t data_len;
|
||||
uint8_t gmac_nonce[GMAC_NONCE_LEN];
|
||||
uint8_t iv[AES_BLOCK_SIZE] = {0};
|
||||
int ret;
|
||||
|
||||
/* Check if frame is invalid length */
|
||||
if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) {
|
||||
cds_err("Invalid frame length");
|
||||
return false;
|
||||
}
|
||||
|
||||
mmie = (struct ieee80211_mmie_16 *)(efrm - sizeof(*mmie));
|
||||
|
||||
/* Check Element ID */
|
||||
if ((mmie->element_id != WLAN_ELEMID_MMIE) ||
|
||||
(mmie->length != (sizeof(*mmie) - 2))) {
|
||||
cds_err("IE is not Mgmt MIC IE or Invalid length");
|
||||
/* IE is not Mgmt MIC IE or invalid length */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Validate IPN */
|
||||
ipn_swap(rx_ipn, mmie->sequence_number);
|
||||
if (qdf_mem_cmp(rx_ipn, ipn, IEEE80211_MMIE_IPNLEN) <= 0) {
|
||||
/* Replay error */
|
||||
cds_debug("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 false;
|
||||
}
|
||||
|
||||
/* Construct AAD */
|
||||
wh = (struct ieee80211_frame *)frm;
|
||||
|
||||
/* Generate 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 */
|
||||
qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * QDF_MAC_ADDR_SIZE);
|
||||
|
||||
data_len = efrm - (uint8_t *) (wh + 1) - IEEE80211_MMIE_GMAC_MICLEN;
|
||||
|
||||
/* IV */
|
||||
qdf_mem_copy(gmac_nonce, wh->i_addr2, QDF_MAC_ADDR_SIZE);
|
||||
qdf_mem_copy(gmac_nonce + QDF_MAC_ADDR_SIZE, rx_ipn,
|
||||
IEEE80211_MMIE_IPNLEN);
|
||||
qdf_mem_copy(iv, gmac_nonce, GMAC_NONCE_LEN);
|
||||
iv[AES_BLOCK_SIZE - 1] = 0x01;
|
||||
|
||||
ret = qdf_crypto_aes_gmac(igtk, key_length, iv, aad,
|
||||
(uint8_t *) (wh + 1), data_len, mic);
|
||||
if (ret) {
|
||||
cds_err("qdf_crypto_aes_gmac failed %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qdf_mem_cmp(mic, mmie->mic, IEEE80211_MMIE_GMAC_MICLEN) != 0) {
|
||||
/* MMIE MIC mismatch */
|
||||
cds_debug("BC/MC MGMT frame MMIE MIC check Failed"
|
||||
" rmic %02X %02X %02X %02X %02X %02X %02X %02X"
|
||||
" %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], mmie->mic[8],
|
||||
mmie->mic[9], mmie->mic[10], mmie->mic[11],
|
||||
mmie->mic[12], mmie->mic[13], mmie->mic[14],
|
||||
mmie->mic[15]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Update IPN */
|
||||
qdf_mem_copy(ipn, rx_ipn, IEEE80211_MMIE_IPNLEN);
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm,
|
||||
uint8_t *efrm, uint16_t key_length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WLAN_FEATURE_11W */
|
||||
|
||||
uint32_t cds_chan_to_freq(uint8_t chan)
|
||||
|
@ -632,30 +632,6 @@ struct wma_version_info {
|
||||
u_int32_t revision;
|
||||
};
|
||||
|
||||
#define CMAC_IPN_LEN (6)
|
||||
#define WMA_IGTK_KEY_INDEX_4 (4)
|
||||
#define WMA_IGTK_KEY_INDEX_5 (5)
|
||||
|
||||
/**
|
||||
* struct wma_igtk_ipn_t - GTK IPN info
|
||||
* @ipn: IPN info
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ipn[CMAC_IPN_LEN];
|
||||
} wma_igtk_ipn_t;
|
||||
|
||||
/**
|
||||
* struct wma_igtk_key_t - GTK key
|
||||
* @key_id: key id
|
||||
*/
|
||||
typedef struct {
|
||||
/* IPN is maintained per iGTK keyID
|
||||
* 0th index for iGTK keyID = 4;
|
||||
* 1st index for iGTK KeyID = 5
|
||||
*/
|
||||
wma_igtk_ipn_t key_id[2];
|
||||
} wma_igtk_key_t;
|
||||
|
||||
struct roam_synch_frame_ind {
|
||||
uint32_t bcn_probe_rsp_len;
|
||||
uint8_t *bcn_probe_rsp;
|
||||
@ -699,7 +675,6 @@ struct wma_invalid_peer_params {
|
||||
* @addBssStaContext: add bss context
|
||||
* @aid: association id
|
||||
* @rmfEnabled: Robust Management Frame (RMF) enabled/disabled
|
||||
* @key: GTK key
|
||||
* @uapsd_cached_val: uapsd cached value
|
||||
* @stats_rsp: stats response
|
||||
* @del_staself_req: delete sta self request
|
||||
@ -750,7 +725,6 @@ struct wma_txrx_node {
|
||||
tAddStaParams *addBssStaContext;
|
||||
uint8_t aid;
|
||||
uint8_t rmfEnabled;
|
||||
wma_igtk_key_t key;
|
||||
uint32_t uapsd_cached_val;
|
||||
void *del_staself_req;
|
||||
bool is_del_sta_defered;
|
||||
@ -2452,17 +2426,6 @@ void wma_update_set_key(uint8_t session_id, bool pairwise,
|
||||
uint8_t key_index,
|
||||
enum wlan_crypto_cipher_type cipher_type);
|
||||
|
||||
/**
|
||||
* wma_get_igtk() - Get the IGTK that was stored in the session earlier
|
||||
* @iface: Interface for which the key is being requested
|
||||
* @key_len: key length
|
||||
* @igtk_key_idx: igtk key idx
|
||||
*
|
||||
* Return: Pointer to the key
|
||||
*/
|
||||
uint8_t *wma_get_igtk(struct wma_txrx_node *iface, uint16_t *key_len,
|
||||
uint16_t igtk_key_idx);
|
||||
|
||||
#ifdef WLAN_FEATURE_MOTION_DETECTION
|
||||
/**
|
||||
* wma_motion_det_host_event_handler - motion detection event handler
|
||||
|
@ -2351,30 +2351,6 @@ static void wma_update_tx_send_params(struct tx_send_params *tx_param,
|
||||
tx_param->preamble_type);
|
||||
}
|
||||
|
||||
#ifdef WLAN_FEATURE_11W
|
||||
uint8_t *wma_get_igtk(struct wma_txrx_node *iface, uint16_t *key_len,
|
||||
uint16_t igtk_key_idx)
|
||||
{
|
||||
struct wlan_crypto_key *crypto_key;
|
||||
|
||||
if (!(igtk_key_idx == WMA_IGTK_KEY_INDEX_4 ||
|
||||
igtk_key_idx == WMA_IGTK_KEY_INDEX_5)) {
|
||||
wma_err("Invalid igtk_key_idx %d", igtk_key_idx);
|
||||
*key_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
crypto_key = wlan_crypto_get_key(iface->vdev, igtk_key_idx);
|
||||
if (!crypto_key) {
|
||||
wma_err("IGTK not found for igtk_idx %d", igtk_key_idx);
|
||||
*key_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
*key_len = crypto_key->keylen;
|
||||
|
||||
return &crypto_key->keyval[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
|
||||
eFrameType frmType, eFrameTxDir txDir, uint8_t tid,
|
||||
wma_tx_dwnld_comp_callback tx_frm_download_comp_cb,
|
||||
@ -2397,8 +2373,6 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
|
||||
uint8_t *pFrame = NULL;
|
||||
void *pPacket = NULL;
|
||||
uint16_t newFrmLen = 0;
|
||||
uint8_t *igtk;
|
||||
uint16_t key_len;
|
||||
#endif /* WLAN_FEATURE_11W */
|
||||
struct wma_txrx_node *iface;
|
||||
struct mac_context *mac;
|
||||
@ -2520,10 +2494,24 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
|
||||
(qdf_nbuf_data(tx_frame));
|
||||
}
|
||||
} else {
|
||||
int8_t igtk_key_id;
|
||||
uint16_t mmie_size;
|
||||
int32_t mgmtcipherset;
|
||||
|
||||
mgmtcipherset = wlan_crypto_get_param(iface->vdev,
|
||||
WLAN_CRYPTO_PARAM_MGMT_CIPHER);
|
||||
if (mgmtcipherset <= 0) {
|
||||
wma_err("Invalid key cipher %d", mgmtcipherset);
|
||||
cds_packet_free((void *)tx_frame);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mgmtcipherset & (1 << WLAN_CRYPTO_CIPHER_AES_CMAC))
|
||||
mmie_size = cds_get_mmie_size();
|
||||
else
|
||||
mmie_size = cds_get_gmac_mmie_size();
|
||||
|
||||
/* Allocate extra bytes for MMIE */
|
||||
newFrmLen = frmLen + IEEE80211_MMIE_LEN;
|
||||
newFrmLen = frmLen + mmie_size;
|
||||
qdf_status = cds_packet_alloc((uint16_t) newFrmLen,
|
||||
(void **)&pFrame,
|
||||
(void **)&pPacket);
|
||||
@ -2539,31 +2527,16 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
|
||||
/*
|
||||
* Initialize the frame with 0's and only fill
|
||||
* MAC header and data. MMIE field will be
|
||||
* filled by cds_attach_mmie API
|
||||
* filled by wlan_crypto_add_mmie API
|
||||
*/
|
||||
qdf_mem_zero(pFrame, newFrmLen);
|
||||
qdf_mem_copy(pFrame, wh, sizeof(*wh));
|
||||
qdf_mem_copy(pFrame + sizeof(*wh),
|
||||
pData + sizeof(*wh), frmLen - sizeof(*wh));
|
||||
igtk_key_id =
|
||||
wlan_crypto_get_default_key_idx(iface->vdev,
|
||||
true);
|
||||
/* Get actual igtk key id adding 4 */
|
||||
igtk_key_id += WMA_IGTK_KEY_INDEX_4;
|
||||
igtk = wma_get_igtk(iface, &key_len, igtk_key_id);
|
||||
if (!igtk) {
|
||||
wma_err_rl("IGTK not present for igtk_key_id %d",
|
||||
igtk_key_id);
|
||||
cds_packet_free((void *)tx_frame);
|
||||
cds_packet_free((void *)pPacket);
|
||||
goto error;
|
||||
}
|
||||
if (!cds_attach_mmie(igtk, iface->key.key_id[
|
||||
igtk_key_id -
|
||||
WMA_IGTK_KEY_INDEX_4].ipn,
|
||||
igtk_key_id,
|
||||
pFrame,
|
||||
pFrame + newFrmLen, newFrmLen)) {
|
||||
|
||||
/* The API expect length without the mmie size */
|
||||
if (!wlan_crypto_add_mmie(iface->vdev, pFrame,
|
||||
frmLen)) {
|
||||
wma_alert("Failed to attach MMIE");
|
||||
/* Free the original packet memory */
|
||||
cds_packet_free((void *)tx_frame);
|
||||
|
@ -2235,17 +2235,6 @@ static void wma_send_vdev_down_req(tp_wma_handle wma,
|
||||
sizeof(*resp), resp);
|
||||
}
|
||||
|
||||
#ifdef WLAN_FEATURE_11W
|
||||
static void wma_clear_iface_key(struct wma_txrx_node *iface)
|
||||
{
|
||||
qdf_mem_zero(&iface->key, sizeof(iface->key));
|
||||
}
|
||||
#else
|
||||
static void wma_clear_iface_key(struct wma_txrx_node *iface)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
QDF_STATUS
|
||||
__wma_handle_vdev_stop_rsp(struct vdev_stop_response *resp_event)
|
||||
{
|
||||
@ -2288,8 +2277,6 @@ __wma_handle_vdev_stop_rsp(struct vdev_stop_response *resp_event)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
/* Clear key information */
|
||||
wma_clear_iface_key(iface);
|
||||
status = mlme_get_vdev_stop_type(iface->vdev, &vdev_stop_type);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
WMA_LOGE("%s: Failed to get wma req msg type for vdev id %d",
|
||||
|
@ -5390,15 +5390,6 @@ void wma_set_peer_ucast_cipher(uint8_t *mac_addr,
|
||||
1 << cipher_cap, mac_addr);
|
||||
}
|
||||
|
||||
static void wma_reset_ipn(struct wma_txrx_node *iface, uint8_t key_index)
|
||||
{
|
||||
if (key_index == WMA_IGTK_KEY_INDEX_4 ||
|
||||
key_index == WMA_IGTK_KEY_INDEX_5)
|
||||
qdf_mem_zero(iface->key.key_id[key_index -
|
||||
WMA_IGTK_KEY_INDEX_4].ipn,
|
||||
CMAC_IPN_LEN);
|
||||
}
|
||||
|
||||
void wma_update_set_key(uint8_t session_id, bool pairwise,
|
||||
uint8_t key_index,
|
||||
enum wlan_crypto_cipher_type cipher_type)
|
||||
@ -5416,10 +5407,9 @@ void wma_update_set_key(uint8_t session_id, bool pairwise,
|
||||
return;
|
||||
}
|
||||
|
||||
if (iface) {
|
||||
wma_reset_ipn(iface, key_index);
|
||||
if (iface)
|
||||
iface->is_waiting_for_key = false;
|
||||
}
|
||||
|
||||
if (!pairwise && iface) {
|
||||
/* Its GTK release the wake lock */
|
||||
wma_debug("Release set key wake lock");
|
||||
|
@ -3092,19 +3092,12 @@ wma_is_ccmp_pn_replay_attack(tp_wma_handle wma, struct ieee80211_frame *wh,
|
||||
*
|
||||
* Return: 0 for success or error code
|
||||
*/
|
||||
|
||||
static
|
||||
int wma_process_bip(tp_wma_handle wma_handle,
|
||||
struct wma_txrx_node *iface,
|
||||
struct ieee80211_frame *wh,
|
||||
qdf_nbuf_t wbuf
|
||||
)
|
||||
int wma_process_bip(tp_wma_handle wma_handle, struct wma_txrx_node *iface,
|
||||
struct ieee80211_frame *wh, qdf_nbuf_t wbuf)
|
||||
{
|
||||
uint16_t mmie_size;
|
||||
uint16_t key_id;
|
||||
uint8_t *efrm;
|
||||
uint8_t *igtk;
|
||||
uint16_t key_len;
|
||||
int32_t mgmtcipherset;
|
||||
enum wlan_crypto_cipher_type key_cipher;
|
||||
|
||||
@ -3112,7 +3105,7 @@ int wma_process_bip(tp_wma_handle wma_handle,
|
||||
|
||||
mgmtcipherset = wlan_crypto_get_param(iface->vdev,
|
||||
WLAN_CRYPTO_PARAM_MGMT_CIPHER);
|
||||
if (!mgmtcipherset || mgmtcipherset < 0) {
|
||||
if (mgmtcipherset <= 0) {
|
||||
wma_err("Invalid key cipher %d", mgmtcipherset);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -3133,28 +3126,16 @@ int wma_process_bip(tp_wma_handle wma_handle,
|
||||
|
||||
/* Check if frame is invalid length */
|
||||
if (efrm - (uint8_t *)wh < sizeof(*wh) + mmie_size) {
|
||||
WMA_LOGE(FL("Invalid frame length"));
|
||||
wma_err("Invalid frame length");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_id = (uint16_t)*(efrm - mmie_size + 2);
|
||||
if (!((key_id == WMA_IGTK_KEY_INDEX_4)
|
||||
|| (key_id == WMA_IGTK_KEY_INDEX_5))) {
|
||||
WMA_LOGE(FL("Invalid KeyID(%d) dropping the frame"), key_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wma_debug("key_cipher %d key_id %d", key_cipher, key_id);
|
||||
|
||||
igtk = wma_get_igtk(iface, &key_len, key_id);
|
||||
switch (key_cipher) {
|
||||
case WLAN_CRYPTO_CIPHER_AES_CMAC:
|
||||
if (!wmi_service_enabled(wma_handle->wmi_handle,
|
||||
wmi_service_sta_pmf_offload)) {
|
||||
if (!cds_is_mmie_valid(igtk, iface->key.key_id[
|
||||
key_id -
|
||||
WMA_IGTK_KEY_INDEX_4].ipn,
|
||||
(uint8_t *)wh, efrm)) {
|
||||
if (!wlan_crypto_is_mmie_valid(iface->vdev,
|
||||
(uint8_t *)wh, efrm)) {
|
||||
wma_debug("BC/MC MIC error or MMIE not present, dropping the frame");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -3164,11 +3145,8 @@ int wma_process_bip(tp_wma_handle wma_handle,
|
||||
case WLAN_CRYPTO_CIPHER_AES_GMAC_256:
|
||||
if (!wmi_service_enabled(wma_handle->wmi_handle,
|
||||
wmi_service_gmac_offload_support)) {
|
||||
if (!cds_is_gmac_mmie_valid(igtk,
|
||||
iface->key.key_id[key_id -
|
||||
WMA_IGTK_KEY_INDEX_4].ipn,
|
||||
(uint8_t *)wh, efrm,
|
||||
key_len)) {
|
||||
if (!wlan_crypto_is_mmie_valid(iface->vdev,
|
||||
(uint8_t *)wh, efrm)) {
|
||||
wma_debug("BC/MC GMAC MIC error or MMIE not present, dropping the frame");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user