diff options
| author | Padma, Santhosh Kumar <skpadma@codeaurora.org> | 2018-02-14 16:07:21 +0530 |
|---|---|---|
| committer | nshrivas <nshrivas@codeaurora.org> | 2018-03-22 03:51:02 -0700 |
| commit | ede4fd7b0cfa4b3be9911e61cb46f0b6e80a7b09 (patch) | |
| tree | 0f1a7661556f7f4d0821c913c640f62c487afa8d | |
| parent | 2badca544776b8408756d8386d5f755bdeb3a68d (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-- | Kbuild | 7 | ||||
| -rw-r--r-- | core/cds/inc/cds_utils.h | 21 | ||||
| -rw-r--r-- | core/cds/src/cds_utils.c | 138 | ||||
| -rw-r--r-- | core/wma/inc/wma.h | 4 | ||||
| -rw-r--r-- | core/wma/src/wma_mgmt.c | 64 |
5 files changed, 217 insertions, 17 deletions
@@ -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; } |
