diff options
Diffstat (limited to 'wcn6740/qcwcn/wifi_hal/wifihal_vendor.cpp')
-rw-r--r-- | wcn6740/qcwcn/wifi_hal/wifihal_vendor.cpp | 644 |
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; +} |