From d8d7dead7d5bb5b928ef750d40d5f3c1f86f81da Mon Sep 17 00:00:00 2001 From: Ashish Kumar Dhanotiya Date: Thu, 24 Oct 2019 14:34:56 +0530 Subject: [PATCH] qcacld-3.0: Add support for oem data event Currently use of comamnd QCA_NL80211_VENDOR_SUBCMD_OEM_DATA is to pass data blobs from Application to FW but there is no mechanism to send the data blobs from FW to Application. To meet the above requirement update the usage of existing OEM DATA command to use it as a vendor event as well to send data blob from host to Application. Change-Id: I502312f25d2754984b86e1cc4e011800a5d4b58a CRs-Fixed: 2573464 --- core/hdd/inc/wlan_hdd_oemdata.h | 17 ++++++++++++ core/hdd/src/wlan_hdd_cfg80211.c | 4 +++ core/hdd/src/wlan_hdd_main.c | 4 +++ core/hdd/src/wlan_hdd_oemdata.c | 38 ++++++++++++++++++++++++++ core/sme/inc/sme_api.h | 38 ++++++++++++++++++++++++++ core/sme/inc/sme_internal.h | 5 ++++ core/sme/src/common/sme_api.c | 36 ++++++++++++++++++++++++ core/wma/inc/wma_internal.h | 12 ++++++++ core/wma/src/wma_main.c | 7 +++++ core/wma/src/wma_utils.c | 47 ++++++++++++++++++++++++++++++++ 10 files changed, 208 insertions(+) diff --git a/core/hdd/inc/wlan_hdd_oemdata.h b/core/hdd/inc/wlan_hdd_oemdata.h index d7ea393f92cd..58b704634078 100644 --- a/core/hdd/inc/wlan_hdd_oemdata.h +++ b/core/hdd/inc/wlan_hdd_oemdata.h @@ -25,6 +25,8 @@ #ifndef __WLAN_HDD_OEM_DATA_H__ #define __WLAN_HDD_OEM_DATA_H__ +#include "wmi_unified_param.h" + struct hdd_context; #ifdef FEATURE_OEM_DATA_SUPPORT @@ -271,4 +273,19 @@ int wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy, #else #define FEATURE_OEM_DATA_VENDOR_COMMANDS #endif + +#ifdef FEATURE_OEM_DATA +/** + * hdd_oem_event_handler_cb() - callback for oem data event + * @oem_event_data: oem data received in the event from the FW + * + * Return: None + */ +void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data); +#else +static inline void hdd_oem_event_handler_cb(void *oem_event_data) +{ +} +#endif + #endif /* __WLAN_HDD_OEM_DATA_H__ */ diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index dcb1d7e1efff..b13bc224b5af 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1574,6 +1574,10 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM, }, + [QCA_NL80211_VENDOR_SUBCMD_OEM_DATA_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_OEM_DATA, + }, }; /** diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 9f2bbbca9bae..47737c39151e 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -13126,6 +13126,7 @@ int hdd_register_cb(struct hdd_context *hdd_ctx) hdd_sme_close_session_callback, hdd_common_roam_callback); + sme_set_oem_data_event_handler_cb(mac_handle, hdd_oem_event_handler_cb); hdd_exit(); return ret; @@ -13152,6 +13153,9 @@ void hdd_deregister_cb(struct hdd_context *hdd_ctx) } mac_handle = hdd_ctx->mac_handle; + + sme_reset_oem_data_event_handler_cb(mac_handle); + sme_deregister_tx_queue_cb(mac_handle); sme_reset_link_layer_stats_ind_cb(mac_handle); diff --git a/core/hdd/src/wlan_hdd_oemdata.c b/core/hdd/src/wlan_hdd_oemdata.c index b4ab85c38e94..184a15a2cfe1 100644 --- a/core/hdd/src/wlan_hdd_oemdata.c +++ b/core/hdd/src/wlan_hdd_oemdata.c @@ -1126,6 +1126,44 @@ oem_data_attr_policy[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1] = { }, }; +void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data) +{ + struct sk_buff *vendor_event; + uint32_t len; + int ret; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + + len = nla_total_size(oem_event_data->data_len) + NLMSG_HDRLEN; + vendor_event = + cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, len, + QCA_NL80211_VENDOR_SUBCMD_OEM_DATA_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + ret = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA, + oem_event_data->data_len, oem_event_data->data); + if (ret) { + hdd_err("OEM event put fails status %d", ret); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + hdd_exit(); +} + /** * __wlan_hdd_cfg80211_oem_data_handler() - the handler for oem data * @wiphy: wiphy structure pointer diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 61d0cc369a10..adec3a0c4fc7 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -3988,4 +3988,42 @@ QDF_STATUS sme_get_ani_level(mac_handle_t mac_handle, uint32_t *freqs, struct wmi_host_ani_level_event *ani, uint8_t num, void *context), void *context); #endif /* FEATURE_ANI_LEVEL_REQUEST */ + +#ifdef FEATURE_OEM_DATA +/** + * sme_set_oem_data_event_handler_cb() - Register oem data event handler + * callback + * @mac_handle: Opaque handle to the MAC context + * @oem_data_event_handler_cb: callback to be registered + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_oem_data_event_handler_cb( + mac_handle_t mac_handle, + void (*oem_data_event_handler_cb) + (const struct oem_data *oem_event_data)); + +/** + * sme_reset_oem_data_event_handler_cb() - De-register oem data event handler + * @mac_handle: Handler return by mac_open + * + * This function De-registers the OEM data event handler callback to SME + * + * Return: None + */ +void sme_reset_oem_data_event_handler_cb(mac_handle_t mac_handle); +#else +static inline QDF_STATUS sme_set_oem_data_event_handler_cb( + mac_handle_t mac_handle, + void (*oem_data_event_handler_cb) + (void *oem_event_data)) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void sme_reset_oem_data_event_handler_cb(mac_handle_t mac_handle) +{ +} +#endif + #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 29cc50851822..cf14a882f30e 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -37,6 +37,7 @@ #include "csr_link_list.h" #include "sme_power_save.h" #include "wmi_unified.h" +#include "wmi_unified_param.h" struct wmi_twt_enable_complete_event_param; /*-------------------------------------------------------------------------- @@ -387,6 +388,10 @@ struct sme_context { beacon_report_cb beacon_report_cb; beacon_pause_cb beacon_pause_cb; #endif +#ifdef FEATURE_OEM_DATA + void (*oem_data_event_handler_cb) + (const struct oem_data *oem_event_data); +#endif }; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 74f8bc4b0b84..e6994358116a 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -16268,3 +16268,39 @@ QDF_STATUS sme_get_ani_level(mac_handle_t mac_handle, uint32_t *freqs, return status; } #endif /* FEATURE_ANI_LEVEL_REQUEST */ + +#ifdef FEATURE_OEM_DATA +QDF_STATUS sme_set_oem_data_event_handler_cb( + mac_handle_t mac_handle, + void (*oem_data_event_handler_cb) + (const struct oem_data *oem_event_data)) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS qdf_status; + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->sme.oem_data_event_handler_cb = oem_data_event_handler_cb; + sme_release_global_lock(&mac->sme); + } + return qdf_status; +} + +void sme_reset_oem_data_event_handler_cb(mac_handle_t mac_handle) +{ + struct mac_context *pmac; + QDF_STATUS qdf_status; + + if (!mac_handle) { + sme_err("mac_handle is not valid"); + return; + } + pmac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&pmac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + pmac->sme.oem_data_event_handler_cb = NULL; + sme_release_global_lock(&pmac->sme); + } +} +#endif diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 1171abacb94e..ce147ccbb5c9 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1902,6 +1902,18 @@ void wma_send_vdev_down(tp_wma_handle wma, struct del_bss_resp *req); int wma_cold_boot_cal_event_handler(void *wma_ctx, uint8_t *event_buff, uint32_t len); +#ifdef FEATURE_OEM_DATA +/** + * wma_oem_event_handler() - oem data event handler + * @wma_ctx: wma handle + * @event_buff: event data + * @len: length of event buffer + * + * Return: Success or Failure status + */ +int wma_oem_event_handler(void *wma_ctx, uint8_t *event_buff, uint32_t len); +#endif + /** * wma_set_roam_triggers() - Send roam trigger bitmap to WMI * @wma_handle: wma handle diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 3107322ea6d5..56402eb74f34 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3179,6 +3179,13 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, wma_cold_boot_cal_event_handler, WMA_RX_WORK_CTX); +#ifdef FEATURE_OEM_DATA + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_oem_data_event_id, + wma_oem_event_handler, + WMA_RX_WORK_CTX); +#endif + #ifdef WLAN_FEATURE_LINK_LAYER_STATS /* Register event handler for processing Link Layer Stats * response from the FW diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index 76e9b573f05b..a2490e6f7639 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -4713,3 +4713,50 @@ int wma_cold_boot_cal_event_handler(void *wma_ctx, uint8_t *event_buff, return 0; } + +#ifdef FEATURE_OEM_DATA +int wma_oem_event_handler(void *wma_ctx, uint8_t *event_buff, uint32_t len) +{ + WMI_OEM_DATA_EVENTID_param_tlvs *param_buf; + struct mac_context *pmac = + (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + wmi_oem_data_event_fixed_param *event; + struct oem_data oem_event_data; + + if (!pmac) { + wma_err("NULL mac handle"); + return -EINVAL; + } + + if (!pmac->sme.oem_data_event_handler_cb) { + wma_err("oem data handler cb is not registered"); + return -EINVAL; + } + + param_buf = + (WMI_OEM_DATA_EVENTID_param_tlvs *)event_buff; + if (!param_buf) { + wma_err("Invalid oem data Event"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + wma_err("Invalid fixed param in oem data Event"); + return -EINVAL; + } + + if (event->data_len > param_buf->num_data) { + wma_err("Invalid data len %d num_data %d", event->data_len, + param_buf->num_data); + return -EINVAL; + } + + oem_event_data.data_len = event->data_len; + oem_event_data.data = param_buf->data; + + pmac->sme.oem_data_event_handler_cb(&oem_event_data); + + return QDF_STATUS_SUCCESS; +} +#endif