qcacld-3.0: Handle attribute OEM_DATA_RESPONSE_EXPECTED

Add support for OEM_DATA_RESPONSE_EXPECTED. Driver waits for the
response from FW when this attribute is set and forward the blob of
data to supplicant.

Change-Id: I3e51809e4f5736b521c26e37afb02396f9c5ed23
CRs-Fixed: 2694556
This commit is contained in:
sheenam monga 2020-05-29 21:54:39 +05:30 • committed by nshrivas
commit 0ec49a71f7
8 changed files with 202 additions and 106 deletions

View file

@ -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)

View file

@ -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

View file

@ -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);

View file

@ -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 <net/cnss_nl.h>
@ -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(&params);
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,

View file

@ -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.

View file

@ -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;

View file

@ -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)

View file

@ -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;
}