summaryrefslogtreecommitdiff
path: root/core/cds
diff options
context:
space:
mode:
authorPadma, Santhosh Kumar <skpadma@codeaurora.org>2018-02-14 16:07:21 +0530
committerSunil Ravi <sunilravi@google.com>2018-12-21 23:51:37 +0000
commitd31c055f0dc15b261c4e82c4276089258c7a01c1 (patch)
treea6ba65c344efcc5db01fc5172f995b2be5acad8b /core/cds
parentf1d91c12845504f59dd84df895fd4155efc5334d (diff)
downloadqcacld-d31c055f0dc15b261c4e82c4276089258c7a01c1.tar.gz
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
Diffstat (limited to 'core/cds')
-rw-r--r--core/cds/inc/cds_utils.h21
-rw-r--r--core/cds/src/cds_utils.c138
2 files changed, 158 insertions, 1 deletions
diff --git a/core/cds/inc/cds_utils.h b/core/cds/inc/cds_utils.h
index 46e24b5fcf..d5d15f324e 100644
--- a/core/cds/inc/cds_utils.h
+++ b/core/cds/inc/cds_utils.h
@@ -168,6 +168,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 bf207f3cbb..cde0bb46c6 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)