summaryrefslogtreecommitdiff
path: root/wcn6740/qcwcn/wifi_hal/wifihal_vendor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wcn6740/qcwcn/wifi_hal/wifihal_vendor.cpp')
-rw-r--r--wcn6740/qcwcn/wifi_hal/wifihal_vendor.cpp644
1 files changed, 644 insertions, 0 deletions
diff --git a/wcn6740/qcwcn/wifi_hal/wifihal_vendor.cpp b/wcn6740/qcwcn/wifi_hal/wifihal_vendor.cpp
new file mode 100644
index 0000000..4837e63
--- /dev/null
+++ b/wcn6740/qcwcn/wifi_hal/wifihal_vendor.cpp
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+#include "wifihal_vendorcommand.h"
+
+#define MAX_INFO 1
+//Singleton Static Instance
+NUDStatsCommand* NUDStatsCommand::mNUDStatsCommandInstance = NULL;
+
+// This function implements creation of Vendor command
+// For NUDStats just call base Vendor command create
+wifi_error NUDStatsCommand::create() {
+ wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
+ if (ret != WIFI_SUCCESS) {
+ return ret;
+ }
+ // insert the oui in the msg
+ ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
+ if (ret != WIFI_SUCCESS)
+ goto out;
+
+ // insert the subcmd in the msg
+ ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
+ if (ret != WIFI_SUCCESS)
+ goto out;
+
+out:
+ return ret;
+}
+
+NUDStatsCommand::NUDStatsCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
+ : WifiVendorCommand(handle, id, vendor_id, subcmd)
+{
+ memset(&mStats, 0,sizeof(nud_stats));
+ mpktInfo = NULL;
+ mnumStats = 0;
+}
+
+NUDStatsCommand::~NUDStatsCommand()
+{
+ mNUDStatsCommandInstance = NULL;
+}
+
+NUDStatsCommand* NUDStatsCommand::instance(wifi_handle handle)
+{
+ if (handle == NULL) {
+ ALOGE("Interface Handle is invalid");
+ return NULL;
+ }
+ if (mNUDStatsCommandInstance == NULL) {
+ mNUDStatsCommandInstance = new NUDStatsCommand(handle, 0,
+ OUI_QCA,
+ QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
+ return mNUDStatsCommandInstance;
+ }
+ else
+ {
+ if (handle != getWifiHandle(mNUDStatsCommandInstance->mInfo))
+ {
+ /* upper layer must have cleaned up the handle and reinitialized,
+ so we need to update the same */
+ ALOGE("Handle different, update the handle");
+ mNUDStatsCommandInstance->mInfo = (hal_info *)handle;
+ }
+ }
+ return mNUDStatsCommandInstance;
+}
+
+void NUDStatsCommand::setSubCmd(u32 subcmd)
+{
+ mSubcmd = subcmd;
+}
+
+void NUDStatsCommand::setHandler(pkt_stats_result_handler handler)
+{
+ mHandler = handler;
+}
+
+wifi_error NUDStatsCommand::requestResponse()
+{
+ return WifiCommand::requestResponse(mMsg);
+}
+
+wifi_error NUDStatsCommand::notifyResponse()
+{
+ wifi_error ret = WIFI_SUCCESS;
+
+ if (mHandler.on_pkt_stats_results) {
+ mHandler.on_pkt_stats_results(&mStats, mnumStats,
+ mpktInfo);
+ } else {
+ ret = WIFI_ERROR_INVALID_ARGS;
+ }
+ return ret;
+}
+
+int NUDStatsCommand::handleResponse(WifiEvent &reply)
+{
+ wifi_error status = WIFI_ERROR_NONE;
+ WifiVendorCommand::handleResponse(reply);
+
+ // Parse the vendordata and get the attribute
+
+ switch(mSubcmd)
+ {
+ case QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET:
+ {
+ struct nlattr *tb_vendor[QCA_ATTR_NUD_STATS_GET_MAX + 1];
+ nud_stats *stats = &mStats;
+
+ memset(stats, 0, sizeof(nud_stats));
+ nla_parse(tb_vendor, QCA_ATTR_NUD_STATS_GET_MAX,
+ (struct nlattr *)mVendorData, mDataLen, NULL);
+
+ if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV])
+ {
+ ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV"
+ " not found", __FUNCTION__);
+ status = WIFI_ERROR_INVALID_ARGS;
+ goto cleanup;
+ }
+ stats->arp_req_count_from_netdev = nla_get_u16(tb_vendor[
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV]);
+
+ if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC])
+ {
+ ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC"
+ " not found", __FUNCTION__);
+ status = WIFI_ERROR_INVALID_ARGS;
+ goto cleanup;
+ }
+ stats->arp_req_count_to_lower_mac = nla_get_u16(tb_vendor[
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC]);
+
+ if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC])
+ {
+ ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC"
+ " not found", __FUNCTION__);
+ status = WIFI_ERROR_INVALID_ARGS;
+ goto cleanup;
+ }
+ stats->arp_req_rx_count_by_lower_mac = nla_get_u16(tb_vendor[
+ QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC]);
+
+ if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS])
+ {
+ ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS"
+ " not found", __FUNCTION__);
+ status = WIFI_ERROR_INVALID_ARGS;
+ goto cleanup;
+ }
+ stats->arp_req_count_tx_success = nla_get_u16(tb_vendor[
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS]);
+
+ if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC])
+ {
+ ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC"
+ " not found", __FUNCTION__);
+ status = WIFI_ERROR_INVALID_ARGS;
+ goto cleanup;
+ }
+ stats->arp_rsp_rx_count_by_lower_mac = nla_get_u16(tb_vendor[
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC]);
+
+ if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC])
+ {
+ ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC"
+ " not found", __FUNCTION__);
+ status = WIFI_ERROR_INVALID_ARGS;
+ goto cleanup;
+ }
+ stats->arp_rsp_rx_count_by_upper_mac = nla_get_u16(tb_vendor[
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC]);
+
+ if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV])
+ {
+ ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV"
+ " not found", __FUNCTION__);
+ status = WIFI_ERROR_INVALID_ARGS;
+ goto cleanup;
+ }
+ stats->arp_rsp_count_to_netdev = nla_get_u16(tb_vendor[
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV]);
+
+ if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP])
+ {
+ ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP"
+ " not found", __FUNCTION__);
+ status = WIFI_ERROR_INVALID_ARGS;
+ goto cleanup;
+ }
+ stats->arp_rsp_count_out_of_order_drop = nla_get_u16(tb_vendor[
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP]);
+
+ if (tb_vendor[QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE])
+ stats->ap_link_active = 1;
+
+ if (tb_vendor[QCA_ATTR_NUD_STATS_IS_DAD])
+ stats->is_duplicate_addr_detection = 1;
+
+ ALOGV(" req_from_netdev %d count_to_lower :%d"
+ " count_by_lower :%d"
+ " count_tx_succ :%d rsp_count_lower :%d"
+ " rsp_count_upper :%d rsp_count_netdev :%d"
+ " out_of_order_drop :%d active_aplink %d"
+ " DAD %d ",
+ stats->arp_req_count_from_netdev,
+ stats->arp_req_count_to_lower_mac,
+ stats->arp_req_rx_count_by_lower_mac,
+ stats->arp_req_count_tx_success,
+ stats->arp_rsp_rx_count_by_lower_mac,
+ stats->arp_rsp_rx_count_by_upper_mac,
+ stats->arp_rsp_count_to_netdev,
+ stats->arp_rsp_count_out_of_order_drop,
+ stats->ap_link_active,
+ stats->is_duplicate_addr_detection);
+
+ if (tb_vendor[QCA_ATTR_NUD_STATS_DATA_PKT_STATS]) {
+ mNUDStatsCommandInstance->GetPktInfo(tb_vendor);
+ }
+ }
+ }
+cleanup:
+ if (status == WIFI_ERROR_INVALID_ARGS)
+ memset(&mStats,0,sizeof(nud_stats));
+ if(mpktInfo != NULL)
+ free(mpktInfo);
+
+ return status;
+}
+
+void NUDStatsCommand::GetPktInfo(struct nlattr **tbvendor)
+{
+ struct nlattr *tb;
+ int rem;
+ cmdData *pkt_stats;
+ char ipv6_address[INET6_ADDRSTRLEN];
+ cmdData pktstats;
+ int nbuff = 0;
+
+ for (tb = (struct nlattr *) nla_data(tbvendor[QCA_ATTR_NUD_STATS_DATA_PKT_STATS]),
+ rem = nla_len(tbvendor[QCA_ATTR_NUD_STATS_DATA_PKT_STATS]);
+ nla_ok(tb, rem); tb = nla_next(tb, &(rem)))
+ {
+ struct nlattr *tb2[QCA_ATTR_NUD_DATA_STATS_MAX + 1];
+ nla_parse(tb2, QCA_ATTR_NUD_DATA_STATS_MAX,
+ (struct nlattr *) nla_data(tb), nla_len(tb), NULL);
+
+ memset(&pktstats, 0, sizeof(cmdData));
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_TYPE])
+ {
+ pktstats.pkt_Type = nla_get_u32(tb2[QCA_ATTR_NUD_STATS_PKT_TYPE]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_DNS_DOMAIN_NAME])
+ {
+ pktstats.domain_name = nla_get_string(tb2[QCA_ATTR_NUD_STATS_PKT_DNS_DOMAIN_NAME]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_SRC_PORT])
+ {
+ pktstats.src_port = nla_get_u32(tb2[QCA_ATTR_NUD_STATS_PKT_SRC_PORT]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_DEST_PORT])
+ {
+ pktstats.dst_port = nla_get_u32(tb2[QCA_ATTR_NUD_STATS_PKT_DEST_PORT]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_DEST_IPV4])
+ {
+ pktstats.ipv4_addr.s_addr = nla_get_u32(tb2[QCA_ATTR_NUD_STATS_PKT_DEST_IPV4]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_DEST_IPV6])
+ {
+ memcpy(pktstats.ipv6_addr, nla_data(tb2[QCA_ATTR_NUD_STATS_PKT_DEST_IPV6]),
+ sizeof(pktstats.ipv6_addr));
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_FROM_NETDEV])
+ {
+ pktstats.stats.pkt_req_count_from_netdev = nla_get_u16(tb2[
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_FROM_NETDEV]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TO_LOWER_MAC])
+ {
+ pktstats.stats.pkt_req_count_to_lower_mac = nla_get_u16(tb2[
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TO_LOWER_MAC]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC])
+ {
+ pktstats.stats.pkt_req_rx_count_by_lower_mac = nla_get_u16(tb2[
+ QCA_ATTR_NUD_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TX_SUCCESS])
+ {
+ pktstats.stats.pkt_req_count_tx_success = nla_get_u16(tb2[
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TX_SUCCESS]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC])
+ {
+ pktstats.stats.pkt_rsp_rx_count_by_lower_mac = nla_get_u16(tb2[
+ QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC])
+ {
+ pktstats.stats.pkt_rsp_rx_count_by_upper_mac = nla_get_u16(tb2[
+ QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_TO_NETDEV])
+ {
+ pktstats.stats.pkt_rsp_count_to_netdev = nla_get_u16(tb2[
+ QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_TO_NETDEV]);
+ }
+
+ if (tb2[QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP])
+ {
+ pktstats.stats.pkt_rsp_count_out_of_order_drop = nla_get_u16(tb2[
+ QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP]);
+ }
+
+ if (inet_ntop(AF_INET6, pktstats.ipv6_addr, ipv6_address,
+ INET6_ADDRSTRLEN) == NULL) {
+ ALOGE("%s: failed to convert ipv6 address format", __FUNCTION__);
+ }
+
+ ALOGV(" pkt_type %d domain_name :%s"
+ " src_port %d dst_port :%d"
+ " ipv4_address :%x ipv6_address %s"
+ " req_from_netdev %d count_to_lower :%d"
+ " count_by_lower :%d"
+ " count_tx_succ :%d rsp_count_lower :%d"
+ " rsp_count_upper :%d rsp_count_netdev :%d"
+ " out_of_order_drop :%d ",
+ pktstats.pkt_Type, pktstats.domain_name,
+ pktstats.src_port, pktstats.dst_port,
+ pktstats.ipv4_addr.s_addr, ipv6_address,
+ pktstats.stats.pkt_req_count_from_netdev,
+ pktstats.stats.pkt_req_count_to_lower_mac,
+ pktstats.stats.pkt_req_rx_count_by_lower_mac,
+ pktstats.stats.pkt_req_count_tx_success,
+ pktstats.stats.pkt_rsp_rx_count_by_lower_mac,
+ pktstats.stats.pkt_rsp_rx_count_by_upper_mac,
+ pktstats.stats.pkt_rsp_count_to_netdev,
+ pktstats.stats.pkt_rsp_count_out_of_order_drop);
+
+ if (nbuff == 0)
+ pkt_stats = (cmdData *)malloc(sizeof(cmdData));
+ else
+ pkt_stats = (cmdData *)realloc(pkt_stats,sizeof(cmdData) * (nbuff + 1));
+
+ mpktInfo = pkt_stats;
+ if (pkt_stats != NULL) {
+ memcpy(&pkt_stats[nbuff], &pktstats,sizeof(cmdData));
+ nbuff++;
+ mnumStats = nbuff;
+ }
+ }
+}
+
+void NUDStatsCommand::copyStats(nud_stats *stats, cmdData *pktstats)
+{
+ memcpy(stats, &mStats, sizeof(nud_stats));
+ pktstats = mpktInfo;
+}
+
+wifi_error wifi_set_nud_stats(wifi_interface_handle iface,
+ u32 gw_addr, cmdData Data)
+{
+ wifi_error ret;
+ NUDStatsCommand *NUDCommand;
+ struct nlattr *nl_data,*nl_pktInfo;
+ interface_info *iinfo = getIfaceInfo(iface);
+ wifi_handle handle = getWifiHandle(iface);
+ cmdData mData = Data;
+ cmdData pktstats = Data;
+
+ ALOGV("gw_addr : %x", gw_addr);
+ NUDCommand = NUDStatsCommand::instance(handle);
+ if (NUDCommand == NULL) {
+ ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
+
+ /* create the message */
+ ret = NUDCommand->create();
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ ret = NUDCommand->set_iface_id(iinfo->name);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ /*add the attributes*/
+ nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data)
+ goto cleanup;
+ /**/
+ ret = NUDCommand->put_flag(QCA_ATTR_NUD_STATS_SET_START);
+
+ ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_GW_IPV4, gw_addr);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ if (mData.pkt_Type) {
+ /*start the packet info attributes in nested*/
+ nl_pktInfo = NUDCommand->attr_start(QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO);
+ if (!nl_pktInfo)
+ goto cleanup;
+ else {
+ ALOGV(" pkt_type %d domain_name :%s"
+ " src_port %d dst_port :%d"
+ " ipv4_address :%x ipv6_address %s",
+ pktstats.pkt_Type, pktstats.domain_name,
+ pktstats.src_port, pktstats.dst_port,
+ pktstats.ipv4_addr.s_addr,pktstats.ipv6_addr);
+
+ for (int i=0; i < MAX_INFO ; i++) {
+ /*add the packet type attributes*/
+ struct nlattr *tb_tmp;
+ tb_tmp = NUDCommand->attr_start(i);
+
+ ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_TYPE,mData.pkt_Type);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ if (mData.domain_name) {
+ /*add the domain name attributes*/
+ ret = NUDCommand->put_string(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DNS_DOMAIN_NAME,
+ mData.domain_name);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+ }
+ /*add the source port attributes*/
+ ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_SRC_PORT,
+ mData.src_port);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ /*add the dest port attributes*/
+ ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_PORT,
+ mData.dst_port);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ /*add the ipv4 address attributes*/
+ ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV4,
+ mData.ipv4_addr.s_addr);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ /*add the ipv6 address attributes*/
+ ret = NUDCommand->put_ipv6_addr(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV6,
+ mData.ipv6_addr);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+ NUDCommand->attr_end(tb_tmp);
+ }
+ }
+ NUDCommand->attr_end(nl_pktInfo);
+ }
+ NUDCommand->attr_end(nl_data);
+
+ ret = NUDCommand->requestResponse();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
+ }
+
+cleanup:
+ return ret;
+}
+
+
+wifi_error wifi_get_nud_stats(wifi_interface_handle iface,
+ pkt_stats_result_handler handler)
+{
+ wifi_error ret;
+ NUDStatsCommand *NUDCommand;
+ struct nlattr *nl_data;
+ interface_info *iinfo = getIfaceInfo(iface);
+ wifi_handle handle = getWifiHandle(iface);
+
+ NUDCommand = NUDStatsCommand::instance(handle);
+ if (NUDCommand == NULL) {
+ ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET);
+
+ NUDCommand->setHandler(handler);
+
+ /* create the message */
+ ret = NUDCommand->create();
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ ret = NUDCommand->set_iface_id(iinfo->name);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+ /*add the attributes*/
+ nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data){
+ ret = WIFI_ERROR_UNKNOWN;
+ goto cleanup;
+ }
+ /**/
+ NUDCommand->attr_end(nl_data);
+
+ ret = NUDCommand->requestResponse();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
+ goto cleanup;
+ }
+
+ ret = NUDCommand->notifyResponse();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
+ goto cleanup;
+ }
+
+cleanup:
+ return ret;
+}
+
+
+wifi_error wifi_clear_nud_stats(wifi_interface_handle iface,
+ cmdData Data)
+{
+ wifi_error ret;
+ NUDStatsCommand *NUDCommand;
+ struct nlattr *nl_data,*nl_pktInfo;
+ interface_info *iinfo = getIfaceInfo(iface);
+ wifi_handle handle = getWifiHandle(iface);
+ cmdData mData = Data;
+
+ NUDCommand = NUDStatsCommand::instance(handle);
+ if (NUDCommand == NULL) {
+ ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
+
+ /* create the message */
+ ret = NUDCommand->create();
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ ret = NUDCommand->set_iface_id(iinfo->name);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ /*add the attributes*/
+ nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nl_data){
+ ret = WIFI_ERROR_UNKNOWN;
+ goto cleanup;
+ }
+ if (mData.pkt_Type) {
+ /*set the packet info attributes in nested*/
+ nl_pktInfo = NUDCommand->attr_start(QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO);
+ if (!nl_pktInfo){
+ ret = WIFI_ERROR_UNKNOWN;
+ goto cleanup;
+ }
+ else {
+ ALOGV(" %s: pkt_type %d domain_name :%s"
+ " src_port %d dst_port :%d"
+ " ipv4_address :%x ipv6_address %s",
+ __FUNCTION__,mData.pkt_Type, mData.domain_name,
+ mData.src_port, mData.dst_port,
+ mData.ipv4_addr.s_addr,mData.ipv6_addr);
+
+ for (int i=0; i < MAX_INFO ; i++) {
+ /*add the packet type attributes*/
+ struct nlattr *tb_tmp;
+ tb_tmp = NUDCommand->attr_start(i);
+
+ ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_TYPE,mData.pkt_Type);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ NUDCommand->attr_end(tb_tmp);
+ }
+ }
+ NUDCommand->attr_end(nl_pktInfo);
+ }
+ NUDCommand->attr_end(nl_data);
+
+ ret = NUDCommand->requestResponse();
+ if (ret != WIFI_SUCCESS)
+ ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
+
+cleanup:
+ return ret;
+}