diff --git a/Kbuild b/Kbuild index 90b5a8e59cd7..c6ea5d2042d8 100644 --- a/Kbuild +++ b/Kbuild @@ -159,6 +159,9 @@ ifneq ($(CONFIG_ROME_IF),sdio) #Flag to enable memdump feature CONFIG_WLAN_FEATURE_MEMDUMP := n + #Flag to enable DISA + CONFIG_WLAN_FEATURE_DISA := y + #Flag to enable Fast Path feature CONFIG_WLAN_FASTPATH := y @@ -420,6 +423,10 @@ ifeq ($(CONFIG_WLAN_FEATURE_MEMDUMP),y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_memdump.o endif +ifeq ($(CONFIG_WLAN_FEATURE_DISA),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_disa.o +endif + ifeq ($(CONFIG_LFR_SUBNET_DETECTION), y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_subnet_detect.o endif @@ -1545,6 +1552,10 @@ ifeq ($(CONFIG_WLAN_FEATURE_MEMDUMP),y) CDEFINES += -DWLAN_FEATURE_MEMDUMP endif +ifeq ($(CONFIG_WLAN_FEATURE_DISA),y) +CDEFINES += -DWLAN_FEATURE_DISA +endif + ifeq ($(CONFIG_LFR_SUBNET_DETECTION), y) CDEFINES += -DFEATURE_LFR_SUBNET_DETECTION endif diff --git a/Kconfig b/Kconfig index bac7403f532d..da483769e7f5 100644 --- a/Kconfig +++ b/Kconfig @@ -132,4 +132,8 @@ config FEATURE_DP_TRACE bool "Enable data path trace feature" default n +config WLAN_FEATURE_DISA + bool "Enable DISA certification feature" + default n + endif # QCA_CLD_WLAN diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index c534a7dd8e39..ce3e7907bb88 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -98,6 +98,7 @@ #include #include "wlan_hdd_lpass.h" #include "wlan_hdd_nan_datapath.h" +#include "wlan_hdd_disa.h" #define g_mode_rates_size (12) #define a_mode_rates_size (8) @@ -8410,7 +8411,18 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_set_fast_roaming - } + }, +#ifdef WLAN_FEATURE_DISA + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_encrypt_decrypt_msg + }, +#endif }; /** diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index 7355b4bea69d..80dbc428c50b 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -429,6 +429,9 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122, QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123, QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124, + + /* Encrypt/Decrypt command */ + QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137, }; /** @@ -2896,6 +2899,44 @@ enum qca_wlan_vendor_drv_info { QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST - 1, }; +/** + * enum qca_wlan_vendor_attr_encryption_test - Attributes to + * validate encryption engine + * + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION: Flag attribute. + * This will be included if the request is for decryption; if not included, + * the request is treated as a request for encryption by default. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER: Unsigned 32-bit value + * indicating the key cipher suite. Takes same values as + * NL80211_ATTR_KEY_CIPHER. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID: Unsigned 8-bit value + * Key Id to be used for encryption + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK: Array of 8-bit values. + * Key (TK) to be used for encryption/decryption + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN: Array of 8-bit values. + * Packet number to be specified for encryption/decryption + * 6 bytes for TKIP/CCMP/GCMP. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA: Array of 8-bit values + * representing the 802.11 packet (header + payload + FCS) that + * needs to be encrypted/decrypted. + * Encrypted/decrypted response from the driver will also be sent + * to userspace with the same attribute. + */ +enum qca_wlan_vendor_attr_encryption_test { + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX = + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST - 1 +}; + struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo); diff --git a/core/hdd/src/wlan_hdd_disa.c b/core/hdd/src/wlan_hdd_disa.c new file mode 100644 index 000000000000..a4153fc5f1db --- /dev/null +++ b/core/hdd/src/wlan_hdd_disa.c @@ -0,0 +1,496 @@ +/* + * Copyright (c) 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. + */ + +/** + * DOC : wlan_hdd_disa.c + * + * WLAN Host Device Driver file for DISA certification + * + */ + +#include "wlan_hdd_disa.h" +#include "sme_api.h" + +#define ENCRYPT_DECRYPT_CONTEXT_MAGIC 0x4475354 +#define WLAN_WAIT_TIME_ENCRYPT_DECRYPT 1000 + + +/** + * hdd_encrypt_decrypt_msg_context - hdd encrypt/decrypt message context + * + * @magic: magic number + * @completion: Completion variable for encrypt/decrypt message + * @response_event: encrypt/decrypt message request wait event + */ +struct hdd_encrypt_decrypt_msg_context { + unsigned int magic; + struct completion completion; + struct sir_encrypt_decrypt_rsp_params response; +}; +static struct hdd_encrypt_decrypt_msg_context encrypt_decrypt_msg_context; + +/** + * hdd_encrypt_decrypt_msg_cb () - sends encrypt/decrypt data to user space + * @encrypt_decrypt_rsp_params: encrypt/decrypt response parameters + * + * Return: none + */ +static void hdd_encrypt_decrypt_msg_cb(void *hdd_context, + struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params) +{ + hdd_context_t *hdd_ctx = hdd_context; + int ret; + struct hdd_encrypt_decrypt_msg_context *context; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + + if (!encrypt_decrypt_rsp_params) { + hdd_err("rsp params is NULL"); + return; + } + + print_hex_dump(KERN_INFO, "Data in hdd_encrypt_decrypt_msg_cb: ", + DUMP_PREFIX_NONE, 16, 1, + encrypt_decrypt_rsp_params->data, + encrypt_decrypt_rsp_params->data_length, 0); + + hdd_err("vdev_id %d,status %d data_length %d", + encrypt_decrypt_rsp_params->vdev_id, + encrypt_decrypt_rsp_params->status, + encrypt_decrypt_rsp_params->data_length); + + spin_lock(&hdd_context_lock); + + context = &encrypt_decrypt_msg_context; + /* The caller presumably timed out so there is nothing we can do */ + if (context->magic != ENCRYPT_DECRYPT_CONTEXT_MAGIC) { + spin_unlock(&hdd_context_lock); + return; + } + + /* context is valid so caller is still waiting */ + context->response = *encrypt_decrypt_rsp_params; + + if (encrypt_decrypt_rsp_params->data_length) { + context->response.data = + qdf_mem_malloc(sizeof(uint8_t) * + encrypt_decrypt_rsp_params->data_length); + if (context->response.data == NULL) { + hdd_err("cdf_mem_alloc failed for data"); + spin_unlock(&hdd_context_lock); + return; + } + qdf_mem_copy(context->response.data, + encrypt_decrypt_rsp_params->data, + encrypt_decrypt_rsp_params->data_length); + } + + /* + * Indicate to calling thread that + * response data is available + */ + context->magic = 0; + + complete(&context->completion); + + spin_unlock(&hdd_context_lock); + + + EXIT(); +} + + +/** + * hdd_encrypt_decrypt_msg_cb () - sends encrypt/decrypt data to user space + * @encrypt_decrypt_rsp_params: encrypt/decrypt response parameters + * + * Return: none + */ +static int hdd_post_encrypt_decrypt_msg_rsp(hdd_context_t *hdd_ctx, + struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + + ENTER(); + + nl_buf_len = encrypt_decrypt_rsp_params->data_length + NLA_HDRLEN; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err(FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + if (encrypt_decrypt_rsp_params->data_length) { + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA, + encrypt_decrypt_rsp_params->data_length, + encrypt_decrypt_rsp_params->data)) { + hdd_err(FL("put fail")); + goto nla_put_failure; + } + } + + cfg80211_vendor_cmd_reply(skb); + EXIT(); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * hdd_fill_encrypt_decrypt_params () - parses data from user space + * and fills encrypt/decrypt parameters + * @encrypt_decrypt_params: encrypt/decrypt request parameters + * @adapter : adapter context + * @data: Pointer to data + * @data_len: Data length + * + Return: 0 on success, negative errno on failure + */ +static int hdd_fill_encrypt_decrypt_params(struct encrypt_decrypt_req_params + *encrypt_decrypt_params, + hdd_adapter_t *adapter, + const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1]; + uint8_t len, mac_hdr_len; + uint8_t *tmp; + uint8_t fc[2]; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + encrypt_decrypt_params->vdev_id = adapter->sessionId; + hdd_err("vdev_id : %d", encrypt_decrypt_params->vdev_id); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION]) { + hdd_err("attr flag NEEDS_DECRYPTION not present"); + encrypt_decrypt_params->key_flag = WMI_ENCRYPT; + } else { + hdd_err("attr flag NEEDS_DECRYPTION present"); + encrypt_decrypt_params->key_flag = WMI_DECRYPT; + } + hdd_err("Key flag : %d", encrypt_decrypt_params->key_flag); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]) { + hdd_err("attr key id failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_idx = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]); + hdd_err("Key Idx : %d", encrypt_decrypt_params->key_idx); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]) { + hdd_err("attr Cipher failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_cipher = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]); + hdd_err("key_cipher : %d", encrypt_decrypt_params->key_cipher); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]) { + hdd_err("attr TK failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]); + if (!encrypt_decrypt_params->key_len) { + hdd_err("Invalid TK length"); + return -EINVAL; + } + hdd_err("Key len : %d", encrypt_decrypt_params->key_len); + + if (encrypt_decrypt_params->key_len > SIR_MAC_MAX_KEY_LENGTH) + encrypt_decrypt_params->key_len = SIR_MAC_MAX_KEY_LENGTH; + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]); + + qdf_mem_copy(encrypt_decrypt_params->key_data, tmp, + encrypt_decrypt_params->key_len); + + print_hex_dump(KERN_INFO, "Key : ", DUMP_PREFIX_NONE, 16, 1, + &encrypt_decrypt_params->key_data, + encrypt_decrypt_params->key_len, 0); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]) { + hdd_err("attr PN failed"); + return -EINVAL; + } + len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]); + if (!len) { + hdd_err("Invalid PN length"); + return -EINVAL; + } + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]); + + qdf_mem_copy(encrypt_decrypt_params->pn, tmp, len); + + print_hex_dump(KERN_INFO, "PN received : ", DUMP_PREFIX_NONE, 16, 1, + &encrypt_decrypt_params->pn, len, 0); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]) { + hdd_err("attr header failed"); + return -EINVAL; + } + len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]); + if (!len) { + hdd_err("Invalid header and payload length"); + return -EINVAL; + } + + hdd_err("Header and Payload length %d ", len); + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]); + + print_hex_dump(KERN_INFO, "Header and Payload received: ", + DUMP_PREFIX_NONE, 16, 1, + tmp, len, 0); + + mac_hdr_len = MIN_MAC_HEADER_LEN; + + /* + * Check to find out address 4. Address 4 is present if ToDS and FromDS + * are 1 and data representation is little endian. + */ + fc[1] = *tmp; + fc[0] = *(tmp + 1); + if ((fc[0] & 0x03) == 0x03) { + hdd_err("Address 4 is present"); + mac_hdr_len += IEEE80211_ADDR_LEN; + } + + /* + * Check to find out Qos control field. Qos control field is present + * if msb of subtype field is 1 and data representation is + * little endian. + */ + if (fc[1] & 0x80) { + hdd_err("Qos control is present"); + mac_hdr_len += QOS_CONTROL_LEN; + } + + hdd_err("mac_hdr_len %d", mac_hdr_len); + + qdf_mem_copy(encrypt_decrypt_params->mac_header, + tmp, mac_hdr_len); + + print_hex_dump(KERN_INFO, "Header received in request: ", + DUMP_PREFIX_NONE, 16, 1, + encrypt_decrypt_params->mac_header, + mac_hdr_len, 0); + + encrypt_decrypt_params->data_len = + len - mac_hdr_len; + + hdd_err("Payload length : %d", encrypt_decrypt_params->data_len); + + if (encrypt_decrypt_params->data_len) { + encrypt_decrypt_params->data = + qdf_mem_malloc(sizeof(uint8_t) * + encrypt_decrypt_params->data_len); + + if (encrypt_decrypt_params->data == NULL) { + hdd_err("cdf_mem_alloc failed for data"); + return -ENOMEM; + } + + qdf_mem_copy(encrypt_decrypt_params->data, + tmp + mac_hdr_len, + encrypt_decrypt_params->data_len); + + print_hex_dump(KERN_INFO, "Data received in request: ", + DUMP_PREFIX_NONE, 16, 1, + encrypt_decrypt_params->data, + encrypt_decrypt_params->data_len, 0); + } + + return 0; +} + +/** + * hdd_encrypt_decrypt_msg () - process encrypt/decrypt message + * @adapter : adapter context + * @hdd_ctx: hdd context + * @data: Pointer to data + * @data_len: Data length + * + Return: 0 on success, negative errno on failure + */ +static int hdd_encrypt_decrypt_msg(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + const void *data, + int data_len) +{ + struct encrypt_decrypt_req_params encrypt_decrypt_params = {0}; + QDF_STATUS qdf_status; + int ret; + struct hdd_encrypt_decrypt_msg_context *context; + unsigned long rc; + + ret = hdd_fill_encrypt_decrypt_params(&encrypt_decrypt_params, + adapter, data, data_len); + if (ret) + return ret; + + spin_lock(&hdd_context_lock); + context = &encrypt_decrypt_msg_context; + context->magic = ENCRYPT_DECRYPT_CONTEXT_MAGIC; + INIT_COMPLETION(context->completion); + spin_unlock(&hdd_context_lock); + + qdf_status = sme_encrypt_decrypt_msg(hdd_ctx->hHal, + &encrypt_decrypt_params); + + qdf_mem_free(encrypt_decrypt_params.data); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Unable to post encrypt/decrypt message"); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->completion, + msecs_to_jiffies(WLAN_WAIT_TIME_ENCRYPT_DECRYPT)); + + spin_lock(&hdd_context_lock); + if (!rc && (context->magic == + ENCRYPT_DECRYPT_CONTEXT_MAGIC)) { + hdd_err("Target response timed out"); + context->magic = 0; + spin_unlock(&hdd_context_lock); + return -ETIMEDOUT; + } + + spin_unlock(&hdd_context_lock); + ret = hdd_post_encrypt_decrypt_msg_rsp(hdd_ctx, + &encrypt_decrypt_msg_context.response); + if (ret) + hdd_err("Failed to post encrypt/decrypt message response"); + + qdf_mem_free(encrypt_decrypt_msg_context.response.data); + + EXIT(); + return ret; +} + +/** + * hdd_encrypt_decrypt_init () - exposes encrypt/decrypt initialization + * functionality + * @hdd_ctx: hdd context + * + Return: 0 on success, negative errno on failure + */ +int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + + init_completion(&encrypt_decrypt_msg_context.completion); + + status = sme_encrypt_decrypt_msg_register_callback(hdd_ctx->hHal, + hdd_encrypt_decrypt_msg_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("encrypt/decrypt callback failed %d", status); + return -EINVAL; + } + return 0; +} + +/** + * hdd_encrypt_decrypt_deinit () - exposes encrypt/decrypt deinitialization + * functionality + * @hdd_ctx: hdd context + * + Return: 0 on success, negative errno on failure + */ +int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + + status = sme_encrypt_decrypt_msg_deregister_callback(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("De-register encrypt/decrypt callback failed: %d", + status); + return 0; +} + +/** + * __wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = NULL; + int ret; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + ret = hdd_encrypt_decrypt_msg(adapter, hdd_ctx, data, data_len); + + return ret; +} + +/** + * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_encrypt_decrypt_msg(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/core/hdd/src/wlan_hdd_disa.h b/core/hdd/src/wlan_hdd_disa.h new file mode 100644 index 000000000000..b35c02c5dbbe --- /dev/null +++ b/core/hdd/src/wlan_hdd_disa.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _WLAN_HDD_DISA_H +#define _WLAN_HDD_DISA_H + +#include "wlan_hdd_main.h" +#include "sir_api.h" + +#ifdef WLAN_FEATURE_DISA +/** + * hdd_encrypt_decrypt_init () - exposes encrypt/decrypt initialization + * functionality + * @hdd_ctx: hdd context + * + Return: 0 on success, negative errno on failure + */ +int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx); + +/** + * hdd_encrypt_decrypt_deinit () - exposes encrypt/decrypt deinitialization + * functionality + * @hdd_ctx: hdd context + * + Return: 0 on success, negative errno on failure + */ +int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx); +#else +static inline int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx) +{ + return -ENOTSUPP; +} +static inline int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx) +{ + return -ENOTSUPP; +} +#endif + +#ifdef WLAN_FEATURE_DISA +/** + * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +#endif + +#endif diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 33f9cfc6a96d..9aeee9107f74 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -107,6 +107,7 @@ #include "wlan_hdd_lpass.h" #include "nan_api.h" #include +#include "wlan_hdd_disa.h" #ifdef MODULE #define WLAN_MODULE_NAME module_name(THIS_MODULE) @@ -4695,8 +4696,7 @@ void hdd_wlan_exit(hdd_context_t *hdd_ctx) /* Free up RoC request queue and flush workqueue */ cds_flush_work(&hdd_ctx->roc_req_work); - - + hdd_encrypt_decrypt_deinit(hdd_ctx); wlansap_global_deinit(); wlan_hdd_deinit_tx_rx_histogram(hdd_ctx); wiphy_unregister(wiphy); @@ -7781,6 +7781,7 @@ int hdd_wlan_startup(struct device *dev) goto err_debugfs_exit; memdump_init(); + hdd_encrypt_decrypt_init(hdd_ctx); if (hdd_ctx->config->fIsImpsEnabled) hdd_set_idle_ps_config(hdd_ctx, true); diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 43b6ccd0d892..0fdac5c0c888 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -6536,4 +6536,18 @@ struct sme_update_access_policy_vendor_ie { uint8_t access_policy; }; +/** + * struct sir_encrypt_decrypt_rsp_params - encrypt/decrypt rsp params + * @vdev_id: vdev id + * @status: status + * @data_length: data length + * @data: data pointer + */ +struct sir_encrypt_decrypt_rsp_params { + uint32_t vdev_id; + int32_t status; + uint32_t data_length; + uint8_t *data; +}; + #endif /* __SIR_API_H */ diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index 903f3a6e9500..2b71b5143209 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -633,6 +633,7 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 360) #define SIR_HAL_POWER_DBG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 362) #define SIR_HAL_SET_DTIM_PERIOD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 363) +#define SIR_HAL_ENCRYPT_DECRYPT_MSG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 364) #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 9afb984a9d78..15f845510ef9 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1276,4 +1276,44 @@ QDF_STATUS sme_set_default_scan_ie(tHalHandle hal, uint16_t session_id, */ QDF_STATUS sme_update_session_param(tHalHandle hal, uint8_t session_id, uint32_t param_type, uint32_t param_val); + +/** + * sme_encrypt_decrypt_msg_register_callback() - Registers + * encrypt/decrypt message callback + * + * @hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback in SME + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_encrypt_decrypt_msg_register_callback(tHalHandle hal, + void (*encrypt_decrypt_cb)(void *hdd_context, + struct sir_encrypt_decrypt_rsp_params + *encrypt_decrypt_rsp_params)); + +/** + * sme_encrypt_decrypt_msg_deregister_callback() - Registers + * encrypt/decrypt message callback + * + * @h_hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to de-register its callback in SME + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_encrypt_decrypt_msg_deregister_callback(tHalHandle h_hal); + +/** + * sme_encrypt_decrypt_msg() - handles encrypt/decrypt mesaage + * @hal: HAL handle + * @encrypt_decrypt_params: struct to set encryption/decryption params. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_encrypt_decrypt_msg(tHalHandle hal, + struct encrypt_decrypt_req_params *encrypt_decrypt_params); + #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 51c135ec235c..0afada7cdf73 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -244,6 +244,8 @@ typedef struct tagSmeStruct { p2p_lo_callback p2p_lo_event_callback; void *p2p_lo_event_context; sme_send_oem_data_rsp_msg oem_data_rsp_callback; + void (*encrypt_decrypt_cb)(void *, + struct sir_encrypt_decrypt_rsp_params *); } tSmeStruct, *tpSmeStruct; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 1a04362b8549..2983525148fc 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -16593,3 +16593,134 @@ QDF_STATUS sme_set_default_scan_ie(tHalHandle hal, uint16_t session_id, sms_log(mac_ctx, LOG1, FL("Set default scan IE status %d"), status); return status; } + +/** + * sme_encrypt_decrypt_msg() - handles encrypt/decrypt mesaage + * @hal: HAL handle + * @encrypt_decrypt_params: struct to set encryption/decryption params. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_encrypt_decrypt_msg(tHalHandle hal, + struct encrypt_decrypt_req_params *encrypt_decrypt_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + cds_msg_t cds_msg; + struct encrypt_decrypt_req_params *params; + uint8_t *ptr; + + ptr = qdf_mem_malloc(sizeof(*params) + + encrypt_decrypt_params->data_len); + if (ptr == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to alloc memory for encrypt/decrypt params")); + return QDF_STATUS_E_NOMEM; + } + + params = (struct encrypt_decrypt_req_params *)ptr; + + *params = *encrypt_decrypt_params; + + if (params->data_len) { + params->data = ptr + sizeof(*params); + + qdf_mem_copy(params->data, encrypt_decrypt_params->data, + params->data_len); + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (status == QDF_STATUS_SUCCESS) { + /* Serialize the req through MC thread */ + cds_msg.bodyptr = params; + cds_msg.type = WMA_ENCRYPT_DECRYPT_MSG; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_msg); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Post encrypt/decrypt msg fail")); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(params); + } + sme_release_global_lock(&mac_ctx->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + qdf_mem_free(params); + } + return status; + +} + +/** + * sme_encrypt_decrypt_msg_register_callback() - Registers + * encrypt/decrypt message callback + * + * @hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback in SME + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_encrypt_decrypt_msg_register_callback(tHalHandle hal, + void (*encrypt_decrypt_cb)(void *hdd_context, + struct sir_encrypt_decrypt_rsp_params + *encrypt_decrypt_rsp_params)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + + mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.encrypt_decrypt_cb = encrypt_decrypt_cb; + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + } + return status; +} + +/** + * sme_encrypt_decrypt_msg_deregister_callback() - Registers + * encrypt/decrypt message callback + * + * @h_hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to de-register its callback in SME + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_encrypt_decrypt_msg_deregister_callback(tHalHandle h_hal) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + + mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.encrypt_decrypt_cb = NULL; + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + } + return status; +} diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 08792473b103..f22aea6dac5d 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -415,6 +415,9 @@ static const t_probeTime_dwellTime }; typedef void (*txFailIndCallback)(uint8_t *peer_mac, uint8_t seqNo); +typedef void (*encrypt_decrypt_cb)(struct sir_encrypt_decrypt_rsp_params + *encrypt_decrypt_rsp_params); + /** * enum t_wma_drv_type - wma driver type diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index 951048c535b0..dcd121e37fdb 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -301,4 +301,6 @@ void wma_process_pdev_hw_mode_trans_ind(void *wma, wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry, struct sir_hw_mode_trans_ind *hw_mode_trans_ind); QDF_STATUS wma_set_powersave_config(uint8_t val); +QDF_STATUS wma_encrypt_decrypt_msg(WMA_HANDLE wma, + struct encrypt_decrypt_req_params *encrypt_decrypt_params); #endif diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index dadac756d645..f35044e57d4a 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1214,4 +1214,7 @@ QDF_STATUS wma_process_hal_pwr_dbg_cmd(WMA_HANDLE handle, struct sir_mac_pwr_dbg_cmd * sir_pwr_dbg_params); +int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data, + uint32_t data_len); + #endif diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index e0fe6e4eb35a..89f06c9db0b5 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -474,6 +474,7 @@ #define WMA_SET_PDEV_IE_REQ SIR_HAL_SET_PDEV_IE_REQ #define WMA_UPDATE_WEP_DEFAULT_KEY SIR_HAL_UPDATE_WEP_DEFAULT_KEY #define WMA_SEND_FREQ_RANGE_CONTROL_IND SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND +#define WMA_ENCRYPT_DECRYPT_MSG SIR_HAL_ENCRYPT_DECRYPT_MSG /* Bit 6 will be used to control BD rate for Management frames */ #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index 9a823e8c7932..7850fa73b903 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -8225,3 +8225,108 @@ QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma, uint8_t val) return QDF_STATUS_SUCCESS; } + +/** + * wma_encrypt_decrypt_msg() - + * @encrypt_decrypt_params: encryption/decryption params + * @data_len: data length + * @encrypt_decrypt_cb: encrypt/decrypt callback + * + * This function sends WMI command to check encryption/decryption engine. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_encrypt_decrypt_msg(WMA_HANDLE handle, + struct encrypt_decrypt_req_params *encrypt_decrypt_params) +{ + int ret; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue encrypt/decrypt msg", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (encrypt_decrypt_params == NULL) { + WMA_LOGE("%s: encrypt/decrypt ptr NULL", + __func__); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_encrypt_decrypt_send_cmd(wma->wmi_handle, + encrypt_decrypt_params); + + return ret; +} + +/** + * wma_encrypt_decrypt_msg_handler() - handle encrypt/decrypt data + * indicated by FW + * @handle: wma context + * @data: event buffer + * @data len: length of event buffer + * + * Return: 0 on success + */ +int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID_param_tlvs *param_buf; + wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param *data_event; + struct sir_encrypt_decrypt_rsp_params encrypt_decrypt_rsp_params; + tp_wma_handle wma = handle; + u_int8_t *buf_ptr; + tpAniSirGlobal pmac; + + if (data == NULL) { + WMA_LOGE("%s: invalid pointer", __func__); + return -EINVAL; + } + + if (wma == NULL) { + WMA_LOGE("%s: wma context is NULL", __func__); + return -EINVAL; + } + + WMA_LOGE("%s: received WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID ", + __func__); + + pmac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + + if (!pmac) { + WMA_LOGE("%s: Invalid pmac", __func__); + return -EINVAL; + } + if (!pmac->sme.encrypt_decrypt_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = + (WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID_param_tlvs *)data; + if (!param_buf) { + WMA_LOGE("%s: Invalid response data buf", __func__); + return -EINVAL; + } + + data_event = param_buf->fixed_param; + + encrypt_decrypt_rsp_params.vdev_id = data_event->vdev_id; + encrypt_decrypt_rsp_params.status = data_event->status; + encrypt_decrypt_rsp_params.data_length = data_event->data_length; + + if (encrypt_decrypt_rsp_params.data_length) { + buf_ptr = + (uint8_t *)data_event + + sizeof( + wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param) + + WMI_TLV_HDR_SIZE; + + encrypt_decrypt_rsp_params.data = buf_ptr; + } + + pmac->sme.encrypt_decrypt_cb(pmac->hHdd, &encrypt_decrypt_rsp_params); + + return 0; +} diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 35cf0b88b049..00f1735cc44e 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -2147,6 +2147,10 @@ QDF_STATUS wma_open(void *cds_context, WMI_BPF_CAPABILIY_INFO_EVENTID, wma_get_bpf_caps_event_handler, WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID, + wma_encrypt_decrypt_msg_handler, + WMA_RX_SERIALIZER_CTX); wma_ndp_register_all_event_handlers(wma_handle); return QDF_STATUS_SUCCESS; @@ -6303,6 +6307,10 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) case WMA_SEND_FREQ_RANGE_CONTROL_IND: wma_enable_disable_caevent_ind(wma_handle, msg->bodyval); break; + case WMA_ENCRYPT_DECRYPT_MSG: + wma_encrypt_decrypt_msg(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; default: WMA_LOGD("unknow msg type %x", msg->type); /* Do Nothing? MSG Body should be freed at here */