diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 7b4b6b2b5963..37766275dc16 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1374,6 +1374,11 @@ struct hdd_adapter { qdf_mutex_t sta_periodic_stats_lock; #endif /* WLAN_FEATURE_PERIODIC_STA_STATS */ qdf_event_t peer_cleanup_done; +#ifdef FEATURE_OEM_DATA + bool oem_data_in_progress; + void *cookie; + bool response_expected; +#endif }; #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station) diff --git a/core/hdd/inc/wlan_hdd_oemdata.h b/core/hdd/inc/wlan_hdd_oemdata.h index 5f117399b502..1fcff5a16f85 100644 --- a/core/hdd/inc/wlan_hdd_oemdata.h +++ b/core/hdd/inc/wlan_hdd_oemdata.h @@ -29,6 +29,9 @@ struct hdd_context; +#ifdef FEATURE_OEM_DATA +#define WLAN_WAIT_TIME_GET_OEM_DATA 1000 +#endif #ifdef FEATURE_OEM_DATA_SUPPORT #ifndef OEM_DATA_REQ_SIZE @@ -284,12 +287,15 @@ extern const struct nla_policy /** * hdd_oem_event_handler_cb() - callback for oem data event * @oem_event_data: oem data received in the event from the FW + * @vdev_id: vdev id * * Return: None */ -void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data); +void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data, + uint8_t vdev_id); #else -static inline void hdd_oem_event_handler_cb(void *oem_event_data) +static inline void hdd_oem_event_handler_cb(void *oem_event_data, + uint8_t vdev_id) { } #endif diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index edee78b3e46f..0f07a5b62c8e 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -13971,7 +13971,6 @@ 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); sme_set_roam_scan_ch_event_cb(mac_handle, hdd_get_roam_scan_ch_cb); status = sme_set_monitor_mode_cb(mac_handle, hdd_sme_monitor_mode_callback); @@ -14005,8 +14004,6 @@ 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 b109dea8635f..805d63dca434 100644 --- a/core/hdd/src/wlan_hdd_oemdata.c +++ b/core/hdd/src/wlan_hdd_oemdata.c @@ -38,7 +38,8 @@ #include "sme_api.h" #include "wlan_nlink_srv.h" #include "wlan_hdd_oemdata.h" - +#include "wlan_osif_request_manager.h" +#include "wlan_hdd_main.h" #ifdef FEATURE_OEM_DATA_SUPPORT #ifdef CNSS_GENL #include @@ -1124,46 +1125,100 @@ oem_data_attr_policy[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1] = { .type = NLA_BINARY, .len = OEM_DATA_MAX_SIZE }, + + [QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED] = {.type = NLA_FLAG}, }; -void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data) +void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data, + uint8_t vdev_id) { struct sk_buff *vendor_event; + struct osif_request *request; uint32_t len; int ret; + struct oem_data *oem_data; struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); - + struct hdd_adapter *hdd_adapter = hdd_get_adapter_by_vdev(hdd_ctx, + vdev_id); 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( + if (hdd_validate_adapter(hdd_adapter)) + return; + + if (!oem_event_data || !(oem_event_data->data)) { + hdd_err("Invalid oem event data"); + return; + } + + if (hdd_adapter->response_expected) { + request = osif_request_get(hdd_adapter->cookie); + if (!request) { + hdd_err("Invalid request"); + return; + } + + oem_data = osif_request_priv(request); + oem_data->data_len = oem_event_data->data_len; + oem_data->data = qdf_mem_malloc(oem_data->data_len); + if (!oem_data->data) { + hdd_err("Memory allocation failure"); + return; + } + qdf_mem_copy(oem_data->data, oem_event_data->data, + oem_data->data_len); + oem_data->vdev_id = hdd_adapter->vdev_id; + osif_request_complete(request); + osif_request_put(request); + } else { + 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; - } + 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; + 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); } - cfg80211_vendor_event(vendor_event, GFP_KERNEL); - hdd_exit(); } +/** + *wlan_hdd_free_oem_data: delete data of priv data + *@priv: osif request private data + * + *Return: void + */ +static void wlan_hdd_free_oem_data(void *priv) +{ + struct oem_data *local_priv = priv; + + if (!local_priv) + return; + + if (local_priv->data) { + qdf_mem_free(local_priv->data); + local_priv->data = NULL; + } +} + /** * __wlan_hdd_cfg80211_oem_data_handler() - the handler for oem data * @wiphy: wiphy structure pointer @@ -1179,17 +1234,34 @@ __wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy, const void *data, int data_len) { struct net_device *dev = wdev->netdev; - QDF_STATUS status; + QDF_STATUS status = QDF_STATUS_SUCCESS; int ret; + struct sk_buff *skb = NULL; struct oem_data oem_data = {0}; + struct oem_data *get_oem_data = NULL; struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1]; + struct osif_request *request = NULL; + struct oem_data *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_GET_OEM_DATA, + .dealloc = wlan_hdd_free_oem_data, + }; ret = wlan_hdd_validate_context(hdd_ctx); if (ret) return ret; + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + if (adapter->oem_data_in_progress) { + hdd_err("oem request already in progress"); + return -EBUSY; + } + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX, data, data_len, oem_data_attr_policy)) { @@ -1203,18 +1275,87 @@ __wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy, } oem_data.data_len = - nla_len(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]); + nla_len(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]); if (!oem_data.data_len) { hdd_err("oem data len is 0!"); return -EINVAL; } - oem_data.vdev_id = adapter->vdev_id; oem_data.data = nla_data(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]); - status = sme_oem_data_cmd(hdd_ctx->mac_handle, &oem_data); + if (tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED]) + adapter->response_expected = nla_get_flag( + tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED]); + + if (adapter->response_expected) { + int skb_len = 0; + + adapter->oem_data_in_progress = true; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("request allocation failure"); + ret = -ENOMEM; + goto err; + } + + adapter->cookie = osif_request_cookie(request); + + status = sme_oem_data_cmd(hdd_ctx->mac_handle, + hdd_oem_event_handler_cb, + &oem_data, adapter->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failure while sending command to fw"); + ret = -EAGAIN; + goto err; + } + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Timedout while retrieving oem get data"); + goto err; + } + + get_oem_data = osif_request_priv(request); + if (!get_oem_data || !(get_oem_data->data)) { + hdd_err("invalid get_oem_data"); + ret = -EINVAL; + goto err; + } + + skb_len = NLMSG_HDRLEN + NLA_HDRLEN + get_oem_data->data_len; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + skb_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + ret = -ENOMEM; + goto err; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA, + get_oem_data->data_len, get_oem_data->data)) { + hdd_err("nla put failure"); + kfree_skb(skb); + ret = -EINVAL; + goto err; + } + wlan_cfg80211_vendor_cmd_reply(skb); + + } else { + status = sme_oem_data_cmd(hdd_ctx->mac_handle, + hdd_oem_event_handler_cb, + &oem_data, adapter->vdev_id); + return qdf_status_to_os_return(status); + } + +err: + if (request) + osif_request_put(request); + adapter->oem_data_in_progress = false; + adapter->response_expected = false; + + return ret; - return qdf_status_to_os_return(status); } int wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy, diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index e0d1ccf96e55..180e49306285 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -768,12 +768,18 @@ QDF_STATUS sme_neighbor_report_request(mac_handle_t mac_handle, /** * sme_oem_data_cmd() - the wrapper to send oem data cmd to wma * @mac_handle: Opaque handle to the global MAC context. + * @@oem_data_event_handler_cb: callback to be registered * @oem_data: the pointer of oem data + * @vdev id: vdev id to fetch adapter * * Return: QDF_STATUS */ QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle, - struct oem_data *oem_data); + void (*oem_data_event_handler_cb) + (const struct oem_data *oem_event_data, + uint8_t vdev_id), + struct oem_data *oem_data, + uint8_t vdev_id); #endif #ifdef FEATURE_OEM_DATA_SUPPORT @@ -4069,43 +4075,6 @@ QDF_STATUS sme_get_ani_level(mac_handle_t mac_handle, uint32_t *freqs, 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 - /** * sme_get_prev_connected_bss_ies() - Get the previous connected AP IEs * @mac_handle: The handle returned by mac_open. diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index ebe541f2b2c2..b186a87fd8ff 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -380,7 +380,9 @@ struct sme_context { #endif #ifdef FEATURE_OEM_DATA void (*oem_data_event_handler_cb) - (const struct oem_data *oem_event_data); + (const struct oem_data *oem_event_data, + uint8_t vdev_id); + uint8_t oem_data_vdev_id; #endif sme_get_raom_scan_ch_callback roam_scan_ch_callback; void *roam_scan_ch_get_context; diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index d822a40272f0..08792b351f3e 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -3700,10 +3700,15 @@ QDF_STATUS sme_oem_req_cmd(mac_handle_t mac_handle, #ifdef FEATURE_OEM_DATA QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle, - struct oem_data *oem_data) + void (*oem_data_event_handler_cb) + (const struct oem_data *oem_event_data, + uint8_t vdev_id), + struct oem_data *oem_data, + uint8_t vdev_id) { QDF_STATUS status; void *wma_handle; + struct mac_context *mac = MAC_CONTEXT(mac_handle); SME_ENTER(); wma_handle = cds_get_context(QDF_MODULE_ID_WMA); @@ -3712,6 +3717,12 @@ QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle, return QDF_STATUS_E_FAILURE; } + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.oem_data_event_handler_cb = oem_data_event_handler_cb; + mac->sme.oem_data_vdev_id = vdev_id; + sme_release_global_lock(&mac->sme); + } status = wma_start_oem_data_cmd(wma_handle, oem_data); if (!QDF_IS_STATUS_SUCCESS(status)) sme_err("fail to call wma_start_oem_data_cmd."); @@ -16062,42 +16073,6 @@ QDF_STATUS sme_get_ani_level(mac_handle_t mac_handle, uint32_t *freqs, } #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 - QDF_STATUS sme_get_prev_connected_bss_ies(mac_handle_t mac_handle, uint8_t vdev_id, uint8_t **ies, uint32_t *ie_len) diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index a2c52afe78c6..4507713ec9a7 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -4950,8 +4950,9 @@ int wma_oem_event_handler(void *wma_ctx, uint8_t *event_buff, uint32_t len) 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); + pmac->sme.oem_data_event_handler_cb(&oem_event_data, + pmac->sme.oem_data_vdev_id); + pmac->sme.oem_data_event_handler_cb = NULL; return QDF_STATUS_SUCCESS; }