summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPadma, Santhosh Kumar <skpadma@codeaurora.org>2018-02-14 16:07:21 +0530
committernshrivas <nshrivas@codeaurora.org>2018-03-22 03:51:02 -0700
commitede4fd7b0cfa4b3be9911e61cb46f0b6e80a7b09 (patch)
tree0f1a7661556f7f4d0821c913c640f62c487afa8d
parent2badca544776b8408756d8386d5f755bdeb3a68d (diff)
qcacld-3.0: Add support for GMAC MIC validation
Add changes to validate MIC for the received protected MC/BC frames with GMAC group management cipher suite. Change-Id: Ie5f60674a452d2d930acc9ff9eb55de37645097a CRs-Fixed: 2164828
-rw-r--r--Kbuild7
-rw-r--r--core/cds/inc/cds_utils.h21
-rw-r--r--core/cds/src/cds_utils.c138
-rw-r--r--core/wma/inc/wma.h4
-rw-r--r--core/wma/src/wma_mgmt.c64
5 files changed, 217 insertions, 17 deletions
diff --git a/Kbuild b/Kbuild
index 5dc5b921ad1f..a4e56f9a0d80 100644
--- a/Kbuild
+++ b/Kbuild
@@ -191,6 +191,9 @@ ifneq ($(CONFIG_ROME_IF),sdio)
#Flag to enable OWE
CONFIG_WLAN_FEATURE_OWE := y
+ #Flag to enable GMAC
+ CONFIG_WLAN_FEATURE_GMAC := y
+
#Flag to enable Fast Path feature
CONFIG_WLAN_FASTPATH := y
@@ -1410,6 +1413,10 @@ ifeq ($(CONFIG_WLAN_FEATURE_OWE),y)
CDEFINES += -DWLAN_FEATURE_OWE
endif
+ifeq ($(CONFIG_WLAN_FEATURE_GMAC),y)
+CDEFINES += -DWLAN_FEATURE_GMAC
+endif
+
ifeq ($(BUILD_DIAG_VERSION),1)
CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT
CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT_CSR
diff --git a/core/cds/inc/cds_utils.h b/core/cds/inc/cds_utils.h
index 852a9b61077f..04b15b8ba6b1 100644
--- a/core/cds/inc/cds_utils.h
+++ b/core/cds/inc/cds_utils.h
@@ -164,6 +164,27 @@ bool cds_is_mmie_valid(uint8_t *key, uint8_t *ipn,
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
+ *
+ * Return: Size of MMIE for GMAC
+ */
+uint8_t cds_get_gmac_mmie_size(void);
+
#endif /* WLAN_FEATURE_11W */
QDF_STATUS sme_send_flush_logs_cmd_to_fw(tpAniSirGlobal pMac);
static inline void cds_host_diag_log_work(qdf_wake_lock_t *lock, uint32_t msec,
diff --git a/core/cds/src/cds_utils.c b/core/cds/src/cds_utils.c
index bf207f3cbb0e..cde0bb46c6c4 100644
--- a/core/cds/src/cds_utils.c
+++ b/core/cds/src/cds_utils.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -61,6 +61,8 @@
#include <crypto/aes.h>
#include "cds_ieee80211_common.h"
+#include <qdf_crypto.h>
+
/*----------------------------------------------------------------------------
* Preprocessor Definitions and Constants
* -------------------------------------------------------------------------*/
@@ -68,6 +70,7 @@
#define IV_SIZE_AES_128 16
#define CMAC_IPN_LEN 6
#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */
+#define GMAC_NONCE_LEN 12
/*----------------------------------------------------------------------------
* Type Declarations
@@ -565,6 +568,139 @@ err_tfm:
return !ret ? true : false;
}
+#if defined(WLAN_FEATURE_GMAC) && \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+uint8_t cds_get_gmac_mmie_size(void)
+{
+ return sizeof(struct ieee80211_mmie_16);
+}
+#else
+uint8_t cds_get_gmac_mmie_size(void)
+{
+ return 0;
+}
+#endif
+
+#ifdef WLAN_FEATURE_GMAC
+/**
+ * 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];
+}
+#endif
+
+#if defined(WLAN_FEATURE_GMAC) && \
+ (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], mic[IEEE80211_MMIE_GMAC_MICLEN];
+ 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))) {
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+ "Invalid frame length");
+ return false;
+ }
+
+ mmie = (struct ieee80211_mmie_16 *)(efrm - sizeof(*mmie));
+
+ /* Check Element ID */
+ if ((mmie->element_id != IEEE80211_ELEMID_MMIE) ||
+ (mmie->length != (sizeof(*mmie) - 2))) {
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+ "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 */
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_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 * IEEE80211_ADDR_LEN);
+
+ data_len = efrm - (uint8_t *) (wh + 1) - IEEE80211_MMIE_GMAC_MICLEN;
+
+ /* IV */
+ qdf_mem_copy(gmac_nonce, wh->i_addr2, IEEE80211_ADDR_LEN);
+ qdf_mem_copy(gmac_nonce + IEEE80211_ADDR_LEN, 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) {
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+ "qdf_crypto_aes_gmac failed %d", ret);
+ return false;
+ }
+
+ if (qdf_mem_cmp(mic, mmie->mic, IEEE80211_MMIE_GMAC_MICLEN) != 0) {
+ /* MMIE MIC mismatch */
+ QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_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)
diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h
index bf863b06ec63..cedc17908e19 100644
--- a/core/wma/inc/wma.h
+++ b/core/wma/inc/wma.h
@@ -970,16 +970,18 @@ typedef struct {
* @key_length: key length
* @key: key
* @key_id: key id
+ * @key_cipher: key cipher
*/
typedef struct {
uint16_t key_length;
- uint8_t key[CSR_AES_KEY_LEN];
+ uint8_t key[CSR_AES_GMAC_256_KEY_LEN];
/* 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];
+ uint32_t key_cipher;
} wma_igtk_key_t;
#endif
diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c
index a9b35c881f91..aa1672a16a76 100644
--- a/core/wma/src/wma_mgmt.c
+++ b/core/wma/src/wma_mgmt.c
@@ -72,6 +72,7 @@
#include <cdp_txrx_cfg.h>
#include <cdp_txrx_cmn.h>
#include <cdp_txrx_misc.h>
+#include <qdf_crypto.h>
/**
* wma_send_bcn_buf_ll() - prepare and send beacon buffer to fw for LL
@@ -1715,6 +1716,7 @@ static QDF_STATUS wma_setup_install_key_cmd(tp_wma_handle wma_handle,
iface = &wma_handle->interfaces[key_params->vdev_id];
if (iface) {
iface->key.key_length = key_params->key_len;
+ iface->key.key_cipher = params.key_cipher;
qdf_mem_copy(iface->key.key,
(const void *)key_params->key_data,
iface->key.key_length);
@@ -3254,32 +3256,64 @@ int wma_process_bip(tp_wma_handle wma_handle,
uint8_t *efrm;
efrm = qdf_nbuf_data(wbuf) + qdf_nbuf_len(wbuf);
- key_id = (uint16_t)*(efrm - cds_get_mmie_size() + 2);
+
+ if (iface->key.key_cipher == WMI_CIPHER_AES_CMAC) {
+ key_id = (uint16_t)*(efrm - cds_get_mmie_size() + 2);
+ } else if (iface->key.key_cipher == WMI_CIPHER_AES_GMAC) {
+ key_id = (uint16_t)*(efrm - cds_get_gmac_mmie_size() + 2);
+ } else {
+ WMA_LOGE(FL("Invalid key cipher %d"), iface->key.key_cipher);
+ return -EINVAL;
+ }
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;
}
- if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
- WMI_SERVICE_STA_PMF_OFFLOAD)) {
- /*
- * if 11w offload is enabled then mmie validation is performed
- * in firmware, host just need to trim the mmie.
- */
- qdf_nbuf_trim_tail(wbuf, cds_get_mmie_size());
- } else {
- if (cds_is_mmie_valid(iface->key.key,
- iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn,
- (uint8_t *) wh, efrm)) {
- WMA_LOGE(FL("Protected BC/MC frame MMIE validation successful"));
- /* Remove MMIE */
+
+ switch (iface->key.key_cipher) {
+ case WMI_CIPHER_AES_CMAC:
+ if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
+ WMI_SERVICE_STA_PMF_OFFLOAD)) {
+ /*
+ * if 11w offload is enabled then mmie validation is
+ * performed in firmware, host just need to trim the
+ * mmie.
+ */
qdf_nbuf_trim_tail(wbuf, cds_get_mmie_size());
} else {
- WMA_LOGE(FL("BC/MC MIC error or MMIE not present, dropping the frame"));
+ if (cds_is_mmie_valid(iface->key.key,
+ iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn,
+ (uint8_t *) wh, efrm)) {
+ WMA_LOGD(FL("Protected BC/MC frame MMIE validation successful"));
+ /* Remove MMIE */
+ qdf_nbuf_trim_tail(wbuf, cds_get_mmie_size());
+ } else {
+ WMA_LOGD(FL("BC/MC MIC error or MMIE not present, dropping the frame"));
+ return -EINVAL;
+ }
+ }
+ break;
+
+ case WMI_CIPHER_AES_GMAC:
+ if (cds_is_gmac_mmie_valid(iface->key.key,
+ iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn,
+ (uint8_t *) wh, efrm, iface->key.key_length)) {
+ WMA_LOGD(FL("Protected BC/MC frame GMAC MMIE validation successful"));
+ /* Remove MMIE */
+ qdf_nbuf_trim_tail(wbuf, cds_get_gmac_mmie_size());
+ } else {
+ WMA_LOGD(FL("BC/MC GMAC MIC error or MMIE not present, dropping the frame"));
return -EINVAL;
}
+ break;
+
+ default:
+ WMA_LOGE(FL("Unsupported key cipher %d"),
+ iface->key.key_cipher);
}
+
return 0;
}