summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmar Singhal <asinghal@qca.qualcomm.com>2014-04-11 15:19:00 -0700
committerPitani Venkata Rajesh Kumar <c_vpitan@qti.qualcomm.com>2014-05-19 11:33:00 +0530
commite81292fa4779ec6ffdcda77b5bb44e02ee47a21a (patch)
tree051c093f4f53e95a2efd005b771a451ceeb813da
parent867ab43fa8edf154d9a298e11346dbab6d388707 (diff)
qcacld: Extended stats implementation
Extended statistics implementation for qcacld. Implement vendor command and sme/wmi layers for passing down the extended statistics command to the firmware. Also implement vendor event to pass back the extended statistics to the userspace. Change-Id: I34c4ae18393154939db3de26f3989ddd82aa7363 CRs-Fixed: 649849
-rw-r--r--CORE/HDD/inc/wlan_hdd_cfg80211.h10
-rw-r--r--CORE/HDD/inc/wlan_hdd_main.h4
-rw-r--r--CORE/HDD/src/wlan_hdd_cfg80211.c103
-rw-r--r--CORE/HDD/src/wlan_hdd_main.c4
-rw-r--r--CORE/MAC/inc/sirApi.h9
-rw-r--r--CORE/MAC/inc/wniApi.h2
-rw-r--r--CORE/MAC/src/include/sirParams.h7
-rw-r--r--CORE/SERVICES/WMA/wma.c121
-rw-r--r--CORE/SME/inc/smeInternal.h6
-rw-r--r--CORE/SME/inc/sme_Api.h18
-rw-r--r--CORE/SME/src/sme_common/sme_Api.c114
-rw-r--r--CORE/WDA/inc/legacy/halMsgApi.h13
-rw-r--r--CORE/WDA/inc/wlan_qct_wda.h5
-rw-r--r--Kbuild8
14 files changed, 421 insertions, 3 deletions
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index dc4ff8a257b7..ee135d67219d 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -120,17 +120,27 @@ typedef struct {
#define QCA_NL80211_VENDOR_ID 0x001374
#define QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY 10
#define QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY 11
+#define QCA_NL80211_VENDOR_SUBCMD_NAN 12
+#define QCA_NL80211_VENDOR_SUBCMD_STATS_EXT 13
enum qca_wlan_vendor_attr
{
QCA_WLAN_VENDOR_ATTR_INVALID = 0,
/* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
QCA_WLAN_VENDOR_ATTR_DFS = 1,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_NAN */
+ QCA_WLAN_VENDOR_ATTR_NAN = 2,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
+ QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
};
+/* Vendor specific sub-command index, may change later due to NAN */
+#ifdef WLAN_FEATURE_STATS_EXT
+#define QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX 1
+#endif /* WLAN_FEATURE_STATS_EXT */
/* Vendor specific sub-command id and their index */
#ifdef FEATURE_WLAN_CH_AVOID
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index eb5514a1b3b3..395c3caf0d00 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -1624,4 +1624,8 @@ void hdd_wlan_green_ap_mc(hdd_context_t *pHddCtx,
hdd_green_ap_event_t event);
#endif
+#ifdef WLAN_FEATURE_STATS_EXT
+void wlan_hdd_cfg80211_stats_ext_init(hdd_context_t *pHddCtx);
+#endif
+
#endif // end #if !defined( WLAN_HDD_MAIN_H )
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 8db9f6006576..808a08c5a31b 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -702,9 +702,9 @@ int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx,
}
vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
- sizeof(tHddAvoidFreqList),
- QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX,
- GFP_KERNEL);
+ sizeof(tHddAvoidFreqList),
+ QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX,
+ GFP_KERNEL);
if (!vendor_event)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
@@ -731,6 +731,13 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
.subcmd = QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY
},
#endif /* FEATURE_WLAN_CH_AVOID */
+
+#ifdef WLAN_FEATURE_STATS_EXT
+ {
+ .vendor_id = QCA_NL80211_VENDOR_ID,
+ .subcmd = QCA_NL80211_VENDOR_SUBCMD_STATS_EXT
+ },
+#endif /* WLAN_FEATURE_STATS_EXT */
};
int is_driver_dfs_capable(struct wiphy *wiphy, struct wireless_dev *wdev,
@@ -770,6 +777,84 @@ int is_driver_dfs_capable(struct wiphy *wiphy, struct wireless_dev *wdev,
}
+#ifdef WLAN_FEATURE_STATS_EXT
+static int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ void *data, int data_len)
+{
+ tStatsExtRequestReq stats_ext_req;
+ struct net_device *dev = wdev->netdev;
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ int ret_val = -1;
+ eHalStatus status;
+
+ stats_ext_req.request_data_len = data_len;
+ stats_ext_req.request_data = data;
+
+ status = sme_StatsExtRequest(pAdapter->sessionId, &stats_ext_req);
+
+ if (eHAL_STATUS_SUCCESS == status)
+ ret_val = 0;
+
+ return ret_val;
+}
+
+static void wlan_hdd_cfg80211_stats_ext_callback(void* ctx, tStatsExtEvent* msg)
+{
+
+ hdd_context_t *pHddCtx = (hdd_context_t *)ctx;
+ struct sk_buff *vendor_event;
+ int status;
+ int ret_val;
+ tStatsExtEvent *data = msg;
+
+ status = wlan_hdd_validate_context(pHddCtx);
+
+ if (0 != status)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: HDD context is not valid", __func__);
+ return;
+ }
+
+
+ vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
+ data->event_data_len +
+ NLMSG_HDRLEN,
+ QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
+ GFP_KERNEL);
+
+ if (!vendor_event)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: cfg80211_vendor_event_alloc failed", __func__);
+ return;
+ }
+
+ ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
+ data->event_data_len, data->event_data);
+
+ if (ret_val)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: QCA_WLAN_VENDOR_ATTR_NAN put fail", __func__);
+ kfree_skb(vendor_event);
+
+ return;
+ }
+
+ cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+
+}
+
+
+void wlan_hdd_cfg80211_stats_ext_init(hdd_context_t *pHddCtx)
+{
+ sme_StatsExtRegisterCallback(pHddCtx->hHal,
+ wlan_hdd_cfg80211_stats_ext_callback);
+}
+
+#endif
const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
{
@@ -780,7 +865,19 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
WIPHY_VENDOR_CMD_NEED_NETDEV |
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = is_driver_dfs_capable
+ },
+
+#ifdef WLAN_FEATURE_STATS_EXT
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_STATS_EXT,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlan_hdd_cfg80211_stats_ext_request
}
+#endif
+
};
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 09d4492ba28a..4144f9ad3ba8 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -11628,6 +11628,10 @@ int hdd_wlan_startup(struct device *dev, v_VOID_t *hif_sc)
(void *)pHddCtx);
#endif
+#ifdef WLAN_FEATURE_STATS_EXT
+ wlan_hdd_cfg80211_stats_ext_init(pHddCtx);
+#endif
+
#if defined(QCA_WIFI_2_0) && !defined(QCA_WIFI_ISOC)
complete(&wlan_start_comp);
#endif
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index cd9e01d0d811..fa75e425d33a 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -4919,4 +4919,13 @@ typedef struct
tANI_U32 param;
} tSirModemPowerStateInd, *tpSirModemPowerStateInd;
+#ifdef WLAN_FEATURE_STATS_EXT
+typedef struct
+{
+ tANI_U32 event_data_len;
+ u_int8_t event_data[];
+} tSirStatsExtEvent, *tpSirStatsExtEvent;
+
+#endif
+
#endif /* __SIR_API_H */
diff --git a/CORE/MAC/inc/wniApi.h b/CORE/MAC/inc/wniApi.h
index da2ec616f8c5..620734960958 100644
--- a/CORE/MAC/inc/wniApi.h
+++ b/CORE/MAC/inc/wniApi.h
@@ -392,6 +392,8 @@ enum eWniMsgTypes
eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ, //Transmit CSA IE in beacons
eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND, //To indicate completion of CSA IE
//update in beacons/probe rsp
+
+ eWNI_SME_STATS_EXT_EVENT,
eWNI_SME_MSG_TYPES_END
};
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index e0d45f4bc300..cae76d46cc35 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -669,6 +669,13 @@ typedef struct sSirMbMsgP2p
#endif
#define SIR_HAL_VDEV_STOP_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 258)
+
+#ifdef WLAN_FEATURE_STATS_EXT
+#define SIR_HAL_STATS_EXT_REQUEST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 259)
+#define SIR_HAL_STATS_EXT_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 260)
+#endif /* WLAN_FEATURE_STATS_EXT */
+
+
#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
// CFG message types
diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c
index 39fe1c78049a..0840e1fd72f1 100644
--- a/CORE/SERVICES/WMA/wma.c
+++ b/CORE/SERVICES/WMA/wma.c
@@ -2871,6 +2871,60 @@ static int wma_vdev_install_key_complete_event_handler(void *handle, u_int8_t *e
return 0;
}
+#ifdef WLAN_FEATURE_STATS_EXT
+static int wma_stats_ext_event_handler(void *handle, u_int8_t *event_buf,
+ u_int32_t len)
+{
+ WMI_STATS_EXT_EVENTID_param_tlvs *param_buf;
+ tSirStatsExtEvent *stats_ext_event;
+ wmi_stats_ext_event_fixed_param *stats_ext_info;
+ VOS_STATUS status;
+ vos_msg_t vos_msg;
+ u_int8_t *buf_ptr;
+ u_int8_t alloc_len;
+
+ WMA_LOGD("%s: Posting stats ext event to SME", __func__);
+
+ param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *)event_buf;
+ if (!param_buf) {
+ WMA_LOGE("%s: Invalid stats ext event buf", __func__);
+ return -EINVAL;
+ }
+
+ stats_ext_info = param_buf->fixed_param;
+ buf_ptr = (u_int8_t *)stats_ext_info;
+
+ alloc_len = sizeof(tSirStatsExtEvent);
+ alloc_len += stats_ext_info->data_len;
+
+ stats_ext_event = (tSirStatsExtEvent *) vos_mem_malloc(alloc_len);
+ if (NULL == stats_ext_event) {
+ WMA_LOGE("%s: Memory allocation failure", __func__);
+ return -ENOMEM;
+ }
+
+ buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE ;
+ stats_ext_event->event_data_len = stats_ext_info->data_len;
+ vos_mem_copy(stats_ext_event->event_data,
+ buf_ptr,
+ stats_ext_event->event_data_len);
+
+ vos_msg.type = eWNI_SME_STATS_EXT_EVENT;
+ vos_msg.bodyptr = (void *)stats_ext_event;
+ vos_msg.bodyval = 0;
+
+ status = vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg);
+ if (status != VOS_STATUS_SUCCESS) {
+ WMA_LOGE("%s: Failed to post stats ext event to SME", __func__);
+ vos_mem_free(stats_ext_event);
+ return -1;
+ }
+
+ WMA_LOGD("%s: stats ext event Posted to SME", __func__);
+ return 0;
+}
+#endif
+
/*
* Allocate and init wmi adaptation layer.
*/
@@ -3154,6 +3208,13 @@ VOS_STATUS WDA_open(v_VOID_t *vos_context, v_VOID_t *os_ctx,
WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
wma_vdev_install_key_complete_event_handler);
+#ifdef WLAN_FEATURE_STATS_EXT
+ /* register for extended stats event */
+ wmi_unified_register_event_handler(wma_handle->wmi_handle,
+ WMI_STATS_EXT_EVENTID,
+ wma_stats_ext_event_handler);
+#endif
+
WMA_LOGD("%s: Exit", __func__);
return VOS_STATUS_SUCCESS;
@@ -16077,6 +16138,56 @@ VOS_STATUS wma_notify_modem_power_state(void *wda_handle,
return VOS_STATUS_SUCCESS;
}
+#ifdef WLAN_FEATURE_STATS_EXT
+VOS_STATUS wma_stats_ext_req(void *wda_handle,
+ tpStatsExtRequest preq)
+{
+ int32_t ret;
+ tp_wma_handle wma = (tp_wma_handle)wda_handle;
+ wmi_req_stats_ext_cmd_fixed_param *cmd;
+ wmi_buf_t buf;
+ u_int16_t len;
+ u_int8_t *buf_ptr;
+
+ len = sizeof(*cmd) + WMI_TLV_HDR_SIZE +
+ preq->request_data_len;
+
+ buf = wmi_buf_alloc(wma->wmi_handle, len);
+ if (!buf) {
+ WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
+ return -ENOMEM;
+ }
+
+ buf_ptr = (u_int8_t *) wmi_buf_data(buf);
+ cmd = (wmi_req_stats_ext_cmd_fixed_param *)buf_ptr;
+
+ WMITLV_SET_HDR(&cmd->tlv_header,
+ WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param,
+ WMITLV_GET_STRUCT_TLVLEN(wmi_req_stats_ext_cmd_fixed_param));
+ cmd->vdev_id = preq->vdev_id;
+ cmd->data_len = preq->request_data_len;
+
+ WMA_LOGD("%s: The data len value is %u and vdev id set is %u ",
+ __func__, preq->request_data_len, preq->vdev_id);
+
+ buf_ptr += sizeof(wmi_req_stats_ext_cmd_fixed_param);
+ WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, cmd->data_len);
+
+ buf_ptr += WMI_TLV_HDR_SIZE;
+ vos_mem_copy(buf_ptr, preq->request_data,
+ cmd->data_len);
+
+ ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
+ WMI_REQUEST_STATS_EXT_CMDID);
+ if (ret != EOK) {
+ WMA_LOGE("%s: Failed to send notify cmd ret = %d", __func__, ret);
+ wmi_buf_free(buf);
+ }
+
+ return ret;
+}
+
+#endif
/*
* function : wma_mc_process_msg
@@ -16480,6 +16591,7 @@ VOS_STATUS wma_mc_process_msg(v_VOID_t *vos_context, vos_msg_t *msg)
(tSirModemPowerStateInd *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
+
case WDA_VDEV_STOP_IND:
wma_vdev_stop_ind(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
@@ -16487,6 +16599,15 @@ VOS_STATUS wma_mc_process_msg(v_VOID_t *vos_context, vos_msg_t *msg)
case WDA_WLAN_RESUME_REQ:
wma_resume_req(wma_handle);
break;
+
+#ifdef WLAN_FEATURE_STATS_EXT
+ case WDA_STATS_EXT_REQUEST:
+ wma_stats_ext_req(wma_handle,
+ (tpStatsExtRequest)(msg->bodyptr));
+ vos_mem_free(msg->bodyptr);
+ break;
+#endif
+
default:
WMA_LOGD("unknow msg type %x", msg->type);
/* Do Nothing? MSG Body should be freed at here */
diff --git a/CORE/SME/inc/smeInternal.h b/CORE/SME/inc/smeInternal.h
index 6cd51d7fed0b..c278a6ae8a27 100644
--- a/CORE/SME/inc/smeInternal.h
+++ b/CORE/SME/inc/smeInternal.h
@@ -118,6 +118,11 @@ typedef enum eSmeState
#define SME_IS_START(pMac) (SME_STATE_STOP != (pMac)->sme.state)
#define SME_IS_READY(pMac) (SME_STATE_READY == (pMac)->sme.state)
+typedef struct sStatsExtEvent {
+ tANI_U32 event_data_len;
+ tANI_U8 event_data[];
+} tStatsExtEvent, *tpStatsExtEvent;
+
typedef struct tagSmeStruct
{
eSmeState state;
@@ -145,6 +150,7 @@ typedef struct tagSmeStruct
#endif /* FEATURE_WLAN_CH_AVOID */
/* Maximum interfaces allowed by the host */
tANI_U8 max_intf_count;
+ void (* StatsExtCallback) (void *, tStatsExtEvent *);
} tSmeStruct, *tpSmeStruct;
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index a8d374c60f67..bf75106870d2 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -54,6 +54,7 @@
#include "btcApi.h"
#include "vos_nvitem.h"
#include "p2p_Api.h"
+#include "smeInternal.h"
#ifdef FEATURE_OEM_DATA_SUPPORT
#include "oemDataApi.h"
@@ -3566,4 +3567,21 @@ eHalStatus sme_ApDisableIntraBssFwd(tHalHandle hHal, tANI_U8 sessionId,
tANI_BOOLEAN disablefwd);
tANI_U32 sme_GetChannelBondingMode5G(tHalHandle hHal);
tANI_U32 sme_GetChannelBondingMode24G(tHalHandle hHal);
+
+#ifdef WLAN_FEATURE_STATS_EXT
+
+typedef struct sStatsExtRequestReq {
+ tANI_U32 request_data_len;
+ tANI_U8* request_data;
+} tStatsExtRequestReq, *tpStatsExtRequestReq;
+
+typedef void (* StatsExtCallback)(void *, tStatsExtEvent *);
+
+void sme_StatsExtRegisterCallback(tHalHandle hHal, StatsExtCallback callback);
+
+eHalStatus sme_StatsExtRequest(tANI_U8 session_id, tpStatsExtRequestReq input);
+
+eHalStatus sme_StatsExtEvent (tHalHandle hHal, void* pMsg);
+
+#endif
#endif //#if !defined( __SME_API_H )
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index b370343f349e..8c1d3f6e404f 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -2632,6 +2632,21 @@ eHalStatus sme_ProcessMsg(tHalHandle hHal, vos_msg_t* pMsg)
"nothing to process");
}
break ;
+
+#ifdef WLAN_FEATURE_STATS_EXT
+ case eWNI_SME_STATS_EXT_EVENT:
+ if (pMsg->bodyptr)
+ {
+ status = sme_StatsExtEvent(hHal, pMsg->bodyptr);
+ vos_mem_free(pMsg->bodyptr);
+ }
+ else
+ {
+ smsLog( pMac, LOGE,
+ "Empty event message for eWNI_SME_STATS_EXT_EVENT, nothing to process");
+ }
+ break;
+#endif
default:
if ( ( pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN )
@@ -12107,3 +12122,102 @@ eHalStatus sme_ApDisableIntraBssFwd(tHalHandle hHal, tANI_U8 sessionId,
return (status);
}
+#ifdef WLAN_FEATURE_STATS_EXT
+
+/******************************************************************************
+ \fn sme_StatsExtRegisterCallback
+
+ \brief
+ a function called to register the callback that send vendor event for stats
+ ext
+
+ \param callback - callback to be registered
+******************************************************************************/
+void sme_StatsExtRegisterCallback(tHalHandle hHal, StatsExtCallback callback)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+
+ pMac->sme.StatsExtCallback = callback;
+}
+
+/******************************************************************************
+ \fn sme_StatsExtRequest
+
+ \brief
+ a function called when HDD receives STATS EXT vendor command from userspace
+
+ \param sessionID - vdevID for the stats ext request
+
+ \param input - Stats Ext Request structure ptr
+
+ \return eHalStatus
+******************************************************************************/
+eHalStatus sme_StatsExtRequest(tANI_U8 session_id, tpStatsExtRequestReq input)
+{
+ vos_msg_t msg;
+ tpStatsExtRequest data;
+ size_t data_len;
+
+ data_len = sizeof(tStatsExtRequest) + input->request_data_len;
+ data = vos_mem_malloc(data_len);
+
+ if (data == NULL) {
+ return eHAL_STATUS_FAILURE;
+ }
+
+ vos_mem_zero(data, data_len);
+ data->vdev_id = session_id;
+ data->request_data_len = input->request_data_len;
+ if (input->request_data_len) {
+ vos_mem_copy(data->request_data,
+ input->request_data, input->request_data_len);
+ }
+
+ msg.type = WDA_STATS_EXT_REQUEST;
+ msg.reserved = 0;
+ msg.bodyptr = data;
+
+ if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA,
+ &msg)) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: Not able to post WDA_STATS_EXT_REQUEST message to WDA",
+ __func__);
+ vos_mem_free(data);
+ return eHAL_STATUS_FAILURE;
+ }
+
+ return eHAL_STATUS_SUCCESS;
+}
+
+
+/******************************************************************************
+ \fn sme_StatsExtEvent
+
+ \brief
+ a callback function called when SME received eWNI_SME_STATS_EXT_EVENT
+ response from WDA
+
+ \param hHal - HAL handle for device
+ \param pMsg - Message body passed from WDA; includes NAN header
+ \return eHalStatus
+******************************************************************************/
+eHalStatus sme_StatsExtEvent(tHalHandle hHal, void* pMsg)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ eHalStatus status = eHAL_STATUS_SUCCESS;
+
+ if (NULL == pMsg) {
+ smsLog(pMac, LOGE, "in %s msg ptr is NULL", __func__);
+ status = eHAL_STATUS_FAILURE;
+ } else {
+ smsLog(pMac, LOG2, "SME: entering %s", __func__);
+
+ if (pMac->sme.StatsExtCallback) {
+ pMac->sme.StatsExtCallback(pMac->pAdapter, (tpStatsExtEvent)pMsg);
+ }
+ }
+
+ return status;
+}
+
+#endif
diff --git a/CORE/WDA/inc/legacy/halMsgApi.h b/CORE/WDA/inc/legacy/halMsgApi.h
index c4b21d4ab021..820c5f9c7f29 100644
--- a/CORE/WDA/inc/legacy/halMsgApi.h
+++ b/CORE/WDA/inc/legacy/halMsgApi.h
@@ -1521,4 +1521,17 @@ typedef __ani_attr_pre_packed struct sDisableIntraBssFwd
tANI_BOOLEAN disableintrabssfwd;
} __ani_attr_packed tDisableIntraBssFwd, *tpDisableIntraBssFwd;
+
+#ifdef WLAN_FEATURE_STATS_EXT
+
+typedef struct sStatsExtRequest
+{
+ tANI_U32 vdev_id;
+ tANI_U32 request_data_len;
+ tANI_U8 request_data[];
+} tStatsExtRequest, *tpStatsExtRequest;
+
+
+#endif
+
#endif /* _HALMSGAPI_H_ */
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index 593f482352bb..27e6f692a744 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -1339,6 +1339,11 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb);
#define WDA_VDEV_STOP_IND SIR_HAL_VDEV_STOP_IND
+#ifdef WLAN_FEATURE_STATS_EXT
+#define WDA_STATS_EXT_REQUEST SIR_HAL_STATS_EXT_REQUEST
+#endif
+
+
tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg);
#define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 // Bit 6 will be used to control BD rate for Management frames
diff --git a/Kbuild b/Kbuild
index d87928e07e25..3a039549c047 100644
--- a/Kbuild
+++ b/Kbuild
@@ -188,6 +188,10 @@ CONFIG_QCA_SINGLE_BINARY_SUPPORT := 0
#Enable collecting target RAM dump after kernel panic
CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := 1
+#Flag to enable Stats Ext implementation
+CONFIG_FEATURE_STATS_EXT := 1
+
+
ifeq ($(CONFIG_CFG80211),y)
HAVE_CFG80211 := 1
else
@@ -1116,6 +1120,10 @@ CDEFINES += -DCONFIG_ENABLE_LINUX_REG
endif
endif
+ifeq ($(CONFIG_FEATURE_STATS_EXT), 1)
+CDEFINES += -DWLAN_FEATURE_STATS_EXT
+endif
+
ifeq ($(CONFIG_QCA_WIFI_2_0), 1)
CDEFINES += -DQCA_WIFI_2_0
endif