wlan: Add Vendor command to set/get NUD debug stats

Add vendor commands to set/reset and get NUD debug stats
from firmware.

Change-Id: Ib016a4580a97d7048c6c1c06ae51264ce0342f27
CRs-Fixed: 1115214
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index b89fa7d..604b327 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -199,6 +199,10 @@
     QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES = 101,
 
     QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105,
+    /* Start / Stop the NUD stats collections */
+    QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149,
+    /* Get the NUD stats, represented by the enum qca_attr_nud_stats_get */
+    QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150,
 };
 
 enum qca_nl80211_vendor_subcmds_index {
@@ -234,8 +238,65 @@
 
     QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX,
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX,
+    QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX,
 };
 
+/**
+ * qca_wlan_vendor_attr_nud_stats_set: attribute to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET. This carry the requisite
+ * information to start / stop the NUD stats collection.
+ */
+enum qca_attr_nud_stats_set {
+    QCA_ATTR_NUD_STATS_SET_INVALID = 0,
+
+    /* Flag to Start / Stop the NUD stats collection
+     * Start - If included , Stop - If not included
+     */
+    QCA_ATTR_NUD_STATS_SET_START = 1,
+    /* IPv4 address of Default Gateway (in network byte order) */
+    QCA_ATTR_NUD_STATS_GW_IPV4 = 2,
+
+    /* keep last */
+    QCA_ATTR_NUD_STATS_SET_LAST,
+    QCA_ATTR_NUD_STATS_SET_MAX =
+            QCA_ATTR_NUD_STATS_SET_LAST - 1,
+};
+
+/**
+ * qca_attr_nud_stats_get: attribute to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carry the requisite
+ * NUD stats collected when queried.
+ */
+enum qca_attr_nud_stats_get {
+    QCA_ATTR_NUD_STATS_GET_INVALID = 0,
+    /* ARP Request Count from net dev */
+    QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1,
+    /* ARP Request Count sent to lower MAC from upper MAC */
+    QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2,
+    /* ARP Request Count received by lower MAC from upper MAC */
+    QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3,
+    /* ARP Request Count successfully transmitted by the device */
+    QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4,
+    /* ARP Response Count received by lower MAC */
+    QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5,
+    /* ARP Response Count received by upper MAC */
+    QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6,
+    /* ARP Response Count delivered to netdev */
+    QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7,
+    /* ARP Response Count delivered to netdev */
+    QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8,
+    /*
+     * Flag indicating if the Stations Link to AP is active.
+     * Active Link - If exists, Inactive link - If not included
+     */
+    QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE= 9,
+    QCA_ATTR_NUD_STATS_AP_LINK_DAD= 10,
+     /* keep last */
+    QCA_ATTR_NUD_STATS_GET_LAST,
+    QCA_ATTR_NUD_STATS_GET_MAX =
+            QCA_ATTR_NUD_STATS_GET_LAST - 1,
+ };
+
 enum qca_wlan_vendor_attr
 {
     QCA_WLAN_VENDOR_ATTR_INVALID = 0,
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 4d9faa1..d5cfd29 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -395,6 +395,35 @@
 } hdd_pmf_stats_t;
 #endif
 
+typedef enum
+{
+   HDD_TX_FRAME_IN_NOT_ASSOCIATED_STATE = 0,
+   HDD_VOS_PACKET_RETURNED_BY_VOSS_IS_NULL,
+   HDD_WLANTL_STAPKTPENDING_RETURNED_ERROR_CODE,
+   HDD_INSERT_TX_QUEUE_FAILED,
+   HDD_FAILED_TO_SIGNAL_TL,
+   HDD_ERROR_ATTACHING_SKB,
+   HDD_FAILURE_EXTRACTING_SKB_FROM_VOS_PKT,
+   HDD_FAILURE_WALKING_PACKET_CHAIN,
+   HDD_STA_RX_ARP_PACKET_REFUSED_IN_NET_STACK
+} HDD_PACKET_DROP_CAUSE;
+
+typedef struct hdd_arp_stats_s
+{
+   uint16   txCount;
+   uint16   rxCount;
+   uint16   txDropped;
+   uint16   rxDropped;
+   uint16   rxDelivered;
+   uint16   rxRefused;
+   uint16   tx_host_fw_sent;
+   uint16   rx_host_drop_reorder;
+   uint16_t tx_fw_cnt;
+   uint16_t rx_fw_cnt;
+   uint16_t tx_ack_cnt;
+   HDD_PACKET_DROP_CAUSE reason;
+} hdd_arp_stats_t;
+
 typedef struct hdd_stats_s
 {
    tCsrSummaryStatsInfo       summary_stat;
@@ -405,6 +434,7 @@
    tCsrPerStaStatsInfo        perStaStats;
    hdd_tx_rx_stats_t          hddTxRxStats;
    hdd_chip_reset_stats_t     hddChipResetStats;
+   hdd_arp_stats_t            hddArpStats;
 #ifdef WLAN_FEATURE_11W
    hdd_pmf_stats_t            hddPmfStats;
 #endif
@@ -1323,6 +1353,8 @@
 #ifdef WLAN_FEATURE_TSF
     struct hdd_tsf_ctx_s tsf_cap_ctx;
 #endif
+    bool con_status;
+    bool dad;
 };
 
 #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station)
@@ -1380,6 +1412,10 @@
 
 #define WLAN_WAIT_TIME_LL_STATS 800
 
+#define WLAN_WAIT_TIME_NUD_STATS 800
+#define WLAN_NUD_STATS_LEN 800
+#define WLAN_NUD_STATS_ARP_PKT_TYPE 1
+
 /* FW memory dump feature
 @TODO : Move this code to a separate file later */
 #define PROCFS_MEMDUMP_DIR  "debug"
@@ -1427,6 +1463,16 @@
     struct completion response_event;
 };
 #endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */
+
+/**
+ * struct hdd_nud_stats_context - hdd NUD stats context
+ *
+ * @response_event: NUD stats request wait event
+ */
+struct hdd_nud_stats_context {
+    struct completion response_event;
+};
+
 #ifdef WLAN_FEATURE_EXTSCAN
 /**
  * struct hdd_ext_scan_context - hdd ext scan context
@@ -1714,6 +1760,7 @@
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
     struct hdd_ll_stats_context ll_stats_context;
 #endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */
+    struct hdd_nud_stats_context nud_stats_context;
 
 #ifdef WLAN_FEATURE_EXTSCAN
     struct hdd_ext_scan_context ext_scan_context;
@@ -2079,6 +2126,19 @@
     return;
 }
 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
+
+/**
+ * hdd_init_nud_stats_ctx() - initialize NUD stats context
+ * @hdd_ctx: Pointer to hdd context
+ *
+ * Return: none
+ */
+static inline void hdd_init_nud_stats_ctx(hdd_context_t *hdd_ctx)
+{
+    init_completion(&hdd_ctx->nud_stats_context.response_event);
+    return;
+}
+
 void hdd_initialize_adapter_common(hdd_adapter_t *pAdapter);
 void hdd_wlan_free_wiphy_channels(struct wiphy *wiphy);
 void wlan_hdd_init_deinit_defer_scan_context(scan_context_t *scan_ctx);
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index b2e69e6..214d9aa 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -7504,6 +7504,355 @@
 
     return ret;
 }
+
+/*
+ * define short names for the global vendor params
+ * used by wlan_hdd_cfg80211_setarp_stats_cmd()
+ */
+#define STATS_SET_INVALID \
+    QCA_ATTR_NUD_STATS_SET_INVALID
+#define STATS_SET_START \
+    QCA_ATTR_NUD_STATS_SET_START
+#define STATS_GW_IPV4 \
+    QCA_ATTR_NUD_STATS_GW_IPV4
+#define STATS_SET_MAX \
+    QCA_ATTR_NUD_STATS_SET_MAX
+
+const struct nla_policy
+qca_wlan_vendor_set_nud_stats[STATS_SET_MAX +1] =
+{
+    [STATS_SET_START] = {.type = NLA_FLAG },
+    [STATS_GW_IPV4] = {.type = NLA_U32 },
+};
+
+/**
+ * hdd_set_nud_stats_cb() - hdd callback api to get status
+ * @data: pointer to adapter
+ * @rsp: status
+ *
+ * Return: None
+ */
+static void hdd_set_nud_stats_cb(void *data, VOS_STATUS rsp)
+{
+
+   hdd_adapter_t *adapter = (hdd_adapter_t *)data;
+
+   if (NULL == adapter)
+      return;
+
+   if (VOS_STATUS_SUCCESS == rsp) {
+      VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                "%s success received STATS_SET_START", __func__);
+   } else {
+      VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                "%s STATS_SET_START Failed!!", __func__);
+   }
+   return;
+}
+
+/**
+ * __wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to apfind configuration data.
+ * @data_len: the length in byte of apfind data.
+ *
+ * This is called when wlan driver needs to send arp stats to
+ * firmware.
+ *
+ * Return: An error code or 0 on success.
+ */
+static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy,
+        struct wireless_dev *wdev,
+        const void *data, int data_len)
+{
+    struct nlattr *tb[STATS_SET_MAX + 1];
+    struct net_device   *dev = wdev->netdev;
+    hdd_adapter_t       *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+    hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+    setArpStatsParams arp_stats_params;
+    int err = 0;
+
+    ENTER();
+
+    err = wlan_hdd_validate_context(hdd_ctx);
+    if (0 != err)
+        return err;
+
+    if (!sme_IsFeatureSupportedByFW(NUD_DEBUG)) {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s NUD_DEBUG feature not supported by firmware!!", __func__);
+        return -EINVAL;
+    }
+
+    err = nla_parse(tb, STATS_SET_MAX, data, data_len,
+                    qca_wlan_vendor_set_nud_stats);
+    if (err)
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s STATS_SET_START ATTR", __func__);
+        return err;
+    }
+
+    if (tb[STATS_SET_START])
+    {
+        if (!tb[STATS_GW_IPV4]) {
+            VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                      "%s STATS_SET_START CMD", __func__);
+            return -EINVAL;
+        }
+        arp_stats_params.flag = true;
+        arp_stats_params.ip_addr = nla_get_u32(tb[STATS_GW_IPV4]);
+    } else {
+        arp_stats_params.flag = false;
+    }
+    if (arp_stats_params.flag) {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                  "%s STATS_SET_START Cleared!!", __func__);
+        vos_mem_zero(&adapter->hdd_stats.hddArpStats, sizeof(adapter->hdd_stats.hddArpStats));
+    }
+
+    arp_stats_params.pkt_type = 1; // ARP packet type
+
+    arp_stats_params.rsp_cb_fn = hdd_set_nud_stats_cb;
+    arp_stats_params.data_ctx = adapter;
+
+    if (eHAL_STATUS_SUCCESS !=
+        sme_set_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s STATS_SET_START CMD Failed!!", __func__);
+        return -EINVAL;
+    }
+
+    EXIT();
+
+    return err;
+}
+
+/**
+ * wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to apfind configuration data.
+ * @data_len: the length in byte of apfind data.
+ *
+ * This is called when wlan driver needs to send arp stats to
+ * firmware.
+ *
+ * Return: An error code or 0 on success.
+ */
+static int wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy,
+        struct wireless_dev *wdev,
+        const void *data, int data_len)
+{
+    int ret;
+
+    vos_ssr_protect(__func__);
+    ret = __wlan_hdd_cfg80211_set_nud_stats(wiphy, wdev, data, data_len);
+    vos_ssr_unprotect(__func__);
+
+    return ret;
+}
+#undef STATS_SET_INVALID
+#undef STATS_SET_START
+#undef STATS_GW_IPV4
+#undef STATS_SET_MAX
+
+/*
+ * define short names for the global vendor params
+ * used by wlan_hdd_cfg80211_setarp_stats_cmd()
+ */
+#define STATS_GET_INVALID \
+    QCA_ATTR_NUD_STATS_SET_INVALID
+#define COUNT_FROM_NETDEV \
+    QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV
+#define COUNT_TO_LOWER_MAC \
+    QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC
+#define RX_COUNT_BY_LOWER_MAC \
+    QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC
+#define COUNT_TX_SUCCESS \
+    QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS
+#define RSP_RX_COUNT_BY_LOWER_MAC \
+    QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC
+#define RSP_RX_COUNT_BY_UPPER_MAC \
+    QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC
+#define RSP_COUNT_TO_NETDEV \
+    QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV
+#define RSP_COUNT_OUT_OF_ORDER_DROP \
+    QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP
+#define AP_LINK_ACTIVE \
+    QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE
+#define AP_LINK_DAD \
+    QCA_ATTR_NUD_STATS_AP_LINK_DAD
+#define STATS_GET_MAX \
+    QCA_ATTR_NUD_STATS_GET_MAX
+
+const struct nla_policy
+qca_wlan_vendor_get_nud_stats[STATS_GET_MAX +1] =
+{
+    [COUNT_FROM_NETDEV] = {.type = NLA_U16 },
+    [COUNT_TO_LOWER_MAC] = {.type = NLA_U16 },
+    [RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 },
+    [COUNT_TX_SUCCESS] = {.type = NLA_U16 },
+    [RSP_RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 },
+    [RSP_RX_COUNT_BY_UPPER_MAC] = {.type = NLA_U16 },
+    [RSP_COUNT_TO_NETDEV] = {.type = NLA_U16 },
+    [RSP_COUNT_OUT_OF_ORDER_DROP] = {.type = NLA_U16 },
+    [AP_LINK_ACTIVE] = {.type = NLA_FLAG },
+    [AP_LINK_DAD] = {.type = NLA_FLAG },
+};
+
+static void hdd_get_nud_stats_cb(void *data, rsp_stats *rsp)
+{
+
+    hdd_adapter_t *adapter = (hdd_adapter_t *)data;
+    hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+    struct hdd_nud_stats_context *context;
+    int status;
+
+    ENTER();
+
+    if (NULL == adapter)
+        return;
+
+    status = wlan_hdd_validate_context(hdd_ctx);
+    if (0 != status) {
+        return;
+    }
+
+    if (!rsp) {
+        hddLog(LOGE, FL("data is null"));
+        return;
+    }
+
+    adapter->hdd_stats.hddArpStats.tx_fw_cnt = rsp->tx_fw_cnt;
+    adapter->hdd_stats.hddArpStats.rx_fw_cnt = rsp->rx_fw_cnt;
+    adapter->hdd_stats.hddArpStats.tx_ack_cnt = rsp->tx_ack_cnt;
+    adapter->dad |= rsp->dad;
+
+    spin_lock(&hdd_context_lock);
+    context = &hdd_ctx->nud_stats_context;
+    complete(&context->response_event);
+    spin_unlock(&hdd_context_lock);
+
+    return;
+}
+static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy,
+        struct wireless_dev *wdev,
+        const void *data, int data_len)
+{
+    int err = 0;
+    unsigned long rc;
+    struct hdd_nud_stats_context *context;
+    struct net_device   *dev = wdev->netdev;
+    hdd_adapter_t       *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+    hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+    getArpStatsParams arp_stats_params;
+    struct sk_buff *skb;
+
+    ENTER();
+
+    err = wlan_hdd_validate_context(hdd_ctx);
+    if (0 != err)
+        return err;
+
+    arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE;
+    arp_stats_params.get_rsp_cb_fn = hdd_get_nud_stats_cb;
+    arp_stats_params.data_ctx = adapter;
+
+    spin_lock(&hdd_context_lock);
+    context = &hdd_ctx->nud_stats_context;
+    INIT_COMPLETION(context->response_event);
+    spin_unlock(&hdd_context_lock);
+
+    if (!sme_IsFeatureSupportedByFW(NUD_DEBUG)) {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s NUD_DEBUG feature not supported by firmware!!", __func__);
+        return -EINVAL;
+    }
+
+    if (eHAL_STATUS_SUCCESS !=
+        sme_get_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s STATS_SET_START CMD Failed!!", __func__);
+        return -EINVAL;
+    }
+
+    rc = wait_for_completion_timeout(&context->response_event,
+            msecs_to_jiffies(WLAN_WAIT_TIME_NUD_STATS));
+    if (!rc)
+    {
+        hddLog(LOGE,
+            FL("Target response timed out request "));
+        return -ETIMEDOUT;
+    }
+
+    skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+            WLAN_NUD_STATS_LEN);
+    if (!skb)
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+                "%s: cfg80211_vendor_cmd_alloc_reply_skb failed",
+                __func__);
+        return -ENOMEM;
+    }
+
+    if (nla_put_u16(skb, COUNT_FROM_NETDEV,
+            adapter->hdd_stats.hddArpStats.txCount) ||
+            nla_put_u16(skb, COUNT_TO_LOWER_MAC,
+            adapter->hdd_stats.hddArpStats.tx_host_fw_sent) ||
+            nla_put_u16(skb, RX_COUNT_BY_LOWER_MAC,
+            adapter->hdd_stats.hddArpStats.tx_fw_cnt) ||
+            nla_put_u16(skb, COUNT_TX_SUCCESS,
+            adapter->hdd_stats.hddArpStats.tx_ack_cnt) ||
+            nla_put_u16(skb, RSP_RX_COUNT_BY_LOWER_MAC,
+            adapter->hdd_stats.hddArpStats.rx_fw_cnt) ||
+            nla_put_u16(skb, RSP_RX_COUNT_BY_UPPER_MAC,
+            adapter->hdd_stats.hddArpStats.rxCount) ||
+            nla_put_u16(skb, RSP_COUNT_TO_NETDEV,
+            adapter->hdd_stats.hddArpStats.rxDelivered) ||
+            nla_put_u16(skb, RSP_COUNT_OUT_OF_ORDER_DROP,
+            adapter->hdd_stats.hddArpStats.rx_host_drop_reorder)) {
+            hddLog(LOGE, FL("nla put fail"));
+            kfree_skb(skb);
+            return -EINVAL;
+    }
+    if (adapter->con_status)
+        nla_put_flag(skb, AP_LINK_ACTIVE);
+    if (adapter->dad)
+        nla_put_flag(skb, AP_LINK_DAD);
+
+    cfg80211_vendor_cmd_reply(skb);
+    return err;
+}
+
+static int wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy,
+        struct wireless_dev *wdev,
+        const void *data, int data_len)
+{
+    int ret;
+
+    vos_ssr_protect(__func__);
+    ret = __wlan_hdd_cfg80211_get_nud_stats(wiphy, wdev, data, data_len);
+    vos_ssr_unprotect(__func__);
+
+    return ret;
+}
+
+#undef QCA_ATTR_NUD_STATS_SET_INVALID
+#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV
+#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC
+#undef QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC
+#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS
+#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC
+#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC
+#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV
+#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP
+#undef QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE
+#undef QCA_ATTR_NUD_STATS_GET_MAX
+
+
+
 #ifdef WLAN_FEATURE_APFIND
 /**
  * __wlan_hdd_cfg80211_apfind_cmd() - set configuration to firmware
@@ -7827,6 +8176,22 @@
         .doit = wlan_hdd_cfg80211_apfind_cmd
     },
 #endif /* WLAN_FEATURE_APFIND */
+    {
+        .info.vendor_id = QCA_NL80211_VENDOR_ID,
+        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET,
+        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+            WIPHY_VENDOR_CMD_NEED_NETDEV |
+            WIPHY_VENDOR_CMD_NEED_RUNNING,
+        .doit = wlan_hdd_cfg80211_set_nud_stats
+    },
+    {
+        .info.vendor_id = QCA_NL80211_VENDOR_ID,
+        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET,
+        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+            WIPHY_VENDOR_CMD_NEED_NETDEV |
+            WIPHY_VENDOR_CMD_NEED_RUNNING,
+        .doit = wlan_hdd_cfg80211_get_nud_stats
+    },
 };
 
 /* vendor specific events */
@@ -7957,7 +8322,10 @@
         .vendor_id = QCA_NL80211_VENDOR_ID,
         .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST
     },
-
+    [QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX] = {
+        .vendor_id = QCA_NL80211_VENDOR_ID,
+        .subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET,
+    },
 };
 
 /*
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 8ffb9fb..7b51c26 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -11821,6 +11821,7 @@
 
 
    hdd_init_ll_stats_ctx(pHddCtx);
+   hdd_init_nud_stats_ctx(pHddCtx);
 
 #ifdef CONFIG_ENABLE_LINUX_REG
    init_completion(&pHddCtx->linux_reg_req);
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 379e905..42b4ffc 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -3802,6 +3802,52 @@
   tANI_U32 reserved2;
 }tAniLoggingInitRsp, *tpAniLoggingInitRsp;
 
+/**
+ * struct rsp_stats - arp packet stats
+ * @status: success or failure
+ * @tx_fw_cnt: tx packets count
+ * @tx_ack_cnt: tx acknowledgement count
+ */
+typedef struct {
+   uint32_t status;
+   uint16_t dad;
+   uint16_t tx_fw_cnt;
+   uint16_t tx_ack_cnt;
+   uint16_t rx_fw_cnt;
+} rsp_stats;
+
+typedef void(*setArpStatsReqCb)(void *data, VOS_STATUS rsp);
+
+/**
+ * struct setArpStatsParams - set/reset arp stats
+ * @flag: enable/disable stats
+ * @pkt_type: type of packet(1 - arp)
+ * @ip_addr: subnet ipv4 address in case of encrypted packets
+ * @rsp_cb_fn: FW response callback api
+ * @data_ctx: parameter for callback api
+ */
+typedef struct {
+   uint8_t flag;
+   uint8_t pkt_type;
+   uint32_t ip_addr;
+   setArpStatsReqCb rsp_cb_fn;
+   void *data_ctx;
+} setArpStatsParams, *psetArpStatsParams;
+
+typedef void(*getArpStatsReqCb)(void *data, rsp_stats *rsp);
+/**
+ * struct getArpStatsParams - get arp stats from firmware
+ * @pkt_type: packet type(1 - ARP)
+ * @get_rsp_cb_fn: FW response callback api
+ * @data_ctx: parameter for callback api
+ */
+typedef struct {
+   uint8_t pkt_type;
+   getArpStatsReqCb get_rsp_cb_fn;
+   void *data_ctx;
+} getArpStatsParams, *pgetArpStatsParams;
+
+
 typedef void(*FWLoggingInitReqCb)(void *fwlogInitCbContext, tAniLoggingInitRsp *pRsp);
 typedef void ( *tGetFrameLogCallback) (void *pContext);
 typedef void(*RssiMonitorReqCb)(void *rssiMonitorCbContext, VOS_STATUS status);
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index a911c33..9752eb7 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -151,6 +151,7 @@
     */
    SAP_OFFLOADS = 65,
    SAP_BUFF_ALLOC = 66,
+   NUD_DEBUG = 68,
    //MAX_FEATURE_SUPPORTED = 128
 } placeHolderInCapBitmap;
 
@@ -792,8 +793,12 @@
 #define SIR_HAL_AP_FIND_IND                (SIR_HAL_ITC_MSG_TYPES_BEGIN + 300)
 #endif/* WLAN_FEATURE_APFIND */
 
-#define SIR_HAL_CAP_TSF_REQ                (SIR_HAL_ITC_MSG_TYPES_BEGIN + 300)
-#define SIR_HAL_GET_TSF_REQ                (SIR_HAL_ITC_MSG_TYPES_BEGIN + 301)
+#define SIR_HAL_CAP_TSF_REQ                (SIR_HAL_ITC_MSG_TYPES_BEGIN + 301)
+#define SIR_HAL_GET_TSF_REQ                (SIR_HAL_ITC_MSG_TYPES_BEGIN + 302)
+
+/* ARP Debug stats */
+#define SIR_HAL_SET_ARP_STATS_REQ          (SIR_HAL_ITC_MSG_TYPES_BEGIN + 303)
+#define SIR_HAL_GET_ARP_STATS_REQ          (SIR_HAL_ITC_MSG_TYPES_BEGIN + 304)
 
 #define SIR_HAL_MSG_TYPES_END              (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index 2ede8eb..0e78c84 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -4023,4 +4023,9 @@
                          tsf_rsp_cb rsp_cb, struct stsf *pTsf,
                          void *pcallbackcontext);
 
+/* ARP DEBUG STATS */
+eHalStatus sme_set_nud_debug_stats(tHalHandle hHal,
+                               psetArpStatsParams pSetStatsParam);
+eHalStatus sme_get_nud_debug_stats(tHalHandle hHal,
+                               pgetArpStatsParams pGetStatsParam);
 #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 69a99fa..0fcac9f 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -14565,6 +14565,77 @@
     return;
 }
 
+/* ARP DEBUG STATS */
+
+/**
+ * sme_set_nud_debug_stats() - sme api to set nud debug stats
+ * @hHal: handle to hal
+ * @pSetStatsParam: pointer to set stats param
+ */
+eHalStatus sme_set_nud_debug_stats(tHalHandle hHal,
+                         setArpStatsParams *pSetStatsParam)
+{
+   setArpStatsParams *arp_set_param;
+   vos_msg_t msg;
+
+   arp_set_param = vos_mem_malloc(sizeof(*arp_set_param));
+   if (arp_set_param == NULL) {
+       VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+               FL("Memory allocation failure"));
+       return VOS_STATUS_E_NOMEM;
+   }
+
+   vos_mem_copy(arp_set_param, pSetStatsParam, sizeof(*arp_set_param));
+
+   msg.type = WDA_SET_ARP_STATS_REQ;
+   msg.reserved = 0;
+   msg.bodyptr = arp_set_param;
+
+   if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) {
+       VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+               FL("Not able to post message to WDA"));
+       vos_mem_free(arp_set_param);
+       return VOS_STATUS_E_FAILURE;
+   }
+
+   return VOS_STATUS_SUCCESS;
+}
+
+/**
+ * sme_get_nud_debug_stats() - sme api to get nud debug stats
+ * @hHal: handle to hal
+ * @pGetStatsParam: pointer to set stats param
+ */
+eHalStatus sme_get_nud_debug_stats(tHalHandle hHal,
+                         getArpStatsParams *pGetStatsParam)
+{
+   getArpStatsParams *arpGetParams;
+   vos_msg_t msg;
+
+   arpGetParams = vos_mem_malloc(sizeof(*arpGetParams));
+   if (arpGetParams == NULL) {
+       VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+               FL("Memory allocation failure"));
+       return VOS_STATUS_E_NOMEM;
+   }
+
+   vos_mem_copy(arpGetParams, pGetStatsParam, sizeof(*arpGetParams));
+
+   msg.type = WDA_GET_ARP_STATS_REQ;
+   msg.reserved = 0;
+   msg.bodyptr = arpGetParams;
+
+   if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) {
+       VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+               FL("Not able to post message to WDA"));
+       vos_mem_free(arpGetParams);
+       return VOS_STATUS_E_FAILURE;
+   }
+
+   return VOS_STATUS_SUCCESS;
+}
+
+
 #ifdef SAP_AUTH_OFFLOAD
 /**
  * sme_set_sap_auth_offload() enable/disable Software AP Auth Offload
diff --git a/CORE/SYS/legacy/src/utils/src/macTrace.c b/CORE/SYS/legacy/src/utils/src/macTrace.c
index 4b2dcd4..ff50926 100644
--- a/CORE/SYS/legacy/src/utils/src/macTrace.c
+++ b/CORE/SYS/legacy/src/utils/src/macTrace.c
@@ -919,6 +919,8 @@
 #endif
         CASE_RETURN_STRING(WDA_CAP_TSF_REQ);
         CASE_RETURN_STRING(WDA_GET_TSF_REQ);
+        CASE_RETURN_STRING(WDA_SET_ARP_STATS_REQ);
+        CASE_RETURN_STRING(WDA_GET_ARP_STATS_REQ);
         default:
             return((tANI_U8*) "UNKNOWN" );
             break;
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index 6f0d9b7..70c8d1d 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -1308,6 +1308,10 @@
 #define WDA_GET_MDNS_STATUS_CMD               SIR_HAL_GET_MDNS_STATUS
 #endif /* MDNS_OFFLOAD */
 
+/* ARP Debug */
+#define WDA_SET_ARP_STATS_REQ                 SIR_HAL_SET_ARP_STATS_REQ
+#define WDA_GET_ARP_STATS_REQ                 SIR_HAL_GET_ARP_STATS_REQ
+
 tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg);
 
 eHalStatus WDA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId,
diff --git a/CORE/WDA/src/wlan_qct_wda.c b/CORE/WDA/src/wlan_qct_wda.c
index 81b9574..332051f 100644
--- a/CORE/WDA/src/wlan_qct_wda.c
+++ b/CORE/WDA/src/wlan_qct_wda.c
@@ -15961,6 +15961,267 @@
     return WLANTL_SuspendDataTx(pWDA->pVosContext, &staId, NULL);
 }
 
+/**
+ * WDA_SetARPStatsParamsRspCallback() - WDA callback api to set/reset arp stats
+ * @wdiSetStatsRsp: pointer to set stats response
+ * @user_data: user data
+ *
+ * Return: None
+ */
+void WDA_SetARPStatsParamsRspCallback(
+                              WDI_SetARPStatsRspParamsType *wdiSetStatsRsp,
+                              void *user_data)
+{
+    tWDA_ReqParams *wda_params = (tWDA_ReqParams *)user_data;
+    setArpStatsParams *arpStatsParams;
+
+    VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+              "ENTER <------ %s " ,__func__);
+
+    if(NULL == wda_params)
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: wda_params received NULL", __func__);
+        VOS_ASSERT(0);
+        return;
+    }
+
+    if(NULL == wda_params->wdaMsgParam)
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: wda_params->wdaMsgParam is NULL", __func__);
+        VOS_ASSERT(0);
+        vos_mem_free(wda_params->wdaWdiApiMsgParam);
+        vos_mem_free(wda_params);
+        return;
+    }
+
+    arpStatsParams = (setArpStatsParams *)wda_params->wdaMsgParam;
+    if(arpStatsParams->rsp_cb_fn)
+    {
+        arpStatsParams->rsp_cb_fn(arpStatsParams->data_ctx,
+                            CONVERT_WDI2VOS_STATUS(wdiSetStatsRsp->status));
+    }
+    else
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: ARP stats callback is NULL", __func__);
+    }
+
+    vos_mem_free(wda_params->wdaWdiApiMsgParam);
+    vos_mem_free(wda_params->wdaMsgParam);
+    vos_mem_free(wda_params);
+    VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+              "EXIT <------ %s " ,__func__);
+    return;
+}
+
+/**
+ * WDA_GetARPStatsParamsRspCallback() - WDA callback api to get arp stats
+ * @wdiGetStatsRsp: pointer to get stats response
+ * @user_data: user data
+ *
+ * Return: None
+ */
+void WDA_GetARPStatsParamsRspCallback(
+                              WDI_GetARPStatsRspParamsType *wdiGetStatsRsp,
+                              void *user_data)
+{
+    tWDA_ReqParams *wda_params = (tWDA_ReqParams *)user_data;
+    getArpStatsParams *arpStatsParams;
+
+    VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+              "ENTER <------ %s " ,__func__);
+
+    if(NULL == wda_params)
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: wda_params received NULL", __func__);
+        VOS_ASSERT(0);
+        return;
+    }
+
+    if(NULL == wda_params->wdaMsgParam)
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: wda_params->wdaMsgParam is NULL", __func__);
+        VOS_ASSERT(0);
+        vos_mem_free(wda_params->wdaWdiApiMsgParam);
+        vos_mem_free(wda_params);
+        return;
+    }
+
+    arpStatsParams = (getArpStatsParams *)wda_params->wdaMsgParam;
+    if(arpStatsParams->get_rsp_cb_fn)
+    {
+        arpStatsParams->get_rsp_cb_fn(arpStatsParams->data_ctx,
+                        (rsp_stats *)wdiGetStatsRsp);
+    }
+    else
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: ARP stats callback is NULL", __func__);
+    }
+
+    vos_mem_free(wda_params->wdaWdiApiMsgParam);
+    vos_mem_free(wda_params->wdaMsgParam);
+    vos_mem_free(wda_params);
+    VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+              "EXIT <------ %s " ,__func__);
+    return;
+}
+
+/**
+ * WDA_ProcessSetARPStatsReq() - WDA api to process set arp stats command
+ * @pWDA: wda handle
+ * @pSetStatsParams: pointer to set arp stats
+ *
+ * Return: VOS_STATUS
+ *   0 Success else failure
+ */
+VOS_STATUS WDA_ProcessSetARPStatsReq(tWDA_CbContext *pWDA,
+                                     setArpStatsParams *pSetStatsParams)
+{
+    WDI_SetARPStatsParamsInfoType *wdiSetStatsParam;
+    tWDA_ReqParams *wda_params;
+    WDI_Status wdi_status = WDI_STATUS_SUCCESS;
+
+    VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+              FL("---> %s"), __func__);
+
+    if(NULL == pSetStatsParams)
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: pSetStatsParams received NULL",
+                  __func__);
+        VOS_ASSERT(0) ;
+        return VOS_STATUS_E_FAULT;
+    }
+
+    wdiSetStatsParam = (WDI_SetARPStatsParamsInfoType *)
+        vos_mem_malloc(sizeof(*wdiSetStatsParam));
+    if (!wdiSetStatsParam) {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "Failed to allocate buffer to send "
+                  "set_dhcp_server_offload cmd");
+        vos_mem_free(pSetStatsParams);
+        return VOS_STATUS_E_NOMEM;
+    }
+
+    vos_mem_zero(wdiSetStatsParam, sizeof(*wdiSetStatsParam));
+
+    wda_params = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ;
+    if(NULL == wda_params)
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: VOS MEM Alloc Failure", __func__);
+        VOS_ASSERT(0);
+        vos_mem_free(wdiSetStatsParam);
+        vos_mem_free(pSetStatsParams);
+        return VOS_STATUS_E_NOMEM;
+    }
+
+    wdiSetStatsParam->flag = pSetStatsParams->flag;
+    wdiSetStatsParam->pkt_type = pSetStatsParams->pkt_type;
+    wdiSetStatsParam->ip_addr = pSetStatsParams->ip_addr;
+
+    /* Store Params pass it to WDI */
+    wda_params->wdaWdiApiMsgParam = (void *)wdiSetStatsParam;
+    wda_params->pWdaContext = pWDA;
+    /* Store param pointer as passed in by caller */
+    wda_params->wdaMsgParam = pSetStatsParams;
+
+    wdi_status = WDI_SetARPStatsReq(wdiSetStatsParam,
+                 (WDI_SetARPStatsRspCb)WDA_SetARPStatsParamsRspCallback,
+                  wda_params);
+
+    if(IS_WDI_STATUS_FAILURE(wdi_status))
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: Failure, free all the memory", __func__);
+        vos_mem_free(wda_params->wdaWdiApiMsgParam) ;
+        vos_mem_free(wda_params->wdaMsgParam);
+        vos_mem_free(wda_params);
+    }
+
+    return wdi_status;
+}
+
+/**
+ * WDA_ProcessGetARPStatsReq() - WDA api to process get arp stats command
+ * @pWDA: wda handle
+ * @pGetStatsParams: pointer to get arp stats
+ *
+ * Return: VOS_STATUS
+ *   0 Success else failure
+ */
+VOS_STATUS WDA_ProcessGetARPStatsReq(tWDA_CbContext *pWDA,
+                                     getArpStatsParams *pGetStatsParams)
+{
+    WDI_GetARPStatsParamsInfoType *wdiGetStatsParam;
+    tWDA_ReqParams *wda_params;
+    WDI_Status wdi_status = WDI_STATUS_SUCCESS;
+
+    VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+              FL("---> %s"), __func__);
+
+    if(NULL == pGetStatsParams)
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: pGetStatsParams received NULL",
+                  __func__);
+        VOS_ASSERT(0) ;
+        return VOS_STATUS_E_FAULT;
+    }
+
+    wdiGetStatsParam = (WDI_GetARPStatsParamsInfoType *)
+        vos_mem_malloc(sizeof(*wdiGetStatsParam));
+    if (!wdiGetStatsParam) {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "Failed to allocate buffer to send "
+                  "set_dhcp_server_offload cmd");
+        vos_mem_free(pGetStatsParams);
+        return VOS_STATUS_E_NOMEM;
+    }
+
+    vos_mem_zero(wdiGetStatsParam, sizeof(*wdiGetStatsParam));
+
+    wda_params = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ;
+    if(NULL == wda_params)
+    {
+        VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                  "%s: VOS MEM Alloc Failure", __func__);
+        VOS_ASSERT(0);
+        vos_mem_free(wdiGetStatsParam);
+        vos_mem_free(pGetStatsParams);
+        return VOS_STATUS_E_NOMEM;
+    }
+
+    wdiGetStatsParam->pkt_type = pGetStatsParams->pkt_type;
+
+    /* Store Params pass it to WDI */
+    wda_params->wdaWdiApiMsgParam = (void *)wdiGetStatsParam;
+    wda_params->pWdaContext = pWDA;
+    /* Store param pointer as passed in by caller */
+    wda_params->wdaMsgParam = pGetStatsParams;
+
+    wdi_status = WDI_GetARPStatsReq(wdiGetStatsParam,
+                 (WDI_GetARPStatsRspCb)WDA_GetARPStatsParamsRspCallback,
+                  wda_params);
+
+    if(IS_WDI_STATUS_FAILURE(wdi_status))
+    {
+         VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                   "%s: Failure, free all the memory", __func__);
+         vos_mem_free(wda_params->wdaWdiApiMsgParam) ;
+         vos_mem_free(wda_params->wdaMsgParam);
+         vos_mem_free(wda_params);
+    }
+
+    return wdi_status;
+}
+
+
 #ifdef DHCP_SERVER_OFFLOAD
 /**
  * wda_process_dhcpserver_offload_req() - wda api to set dhcp server offload
@@ -17414,6 +17675,16 @@
           WDA_ProcessGetTsfReq(pWDA, (tSirCapTsfParams *)pMsg->bodyptr);
           break;
       }
+      case WDA_SET_ARP_STATS_REQ:
+      {
+         WDA_ProcessSetARPStatsReq(pWDA, (setArpStatsParams *)pMsg->bodyptr);
+         break;
+      }
+      case WDA_GET_ARP_STATS_REQ:
+      {
+         WDA_ProcessGetARPStatsReq(pWDA, (getArpStatsParams *)pMsg->bodyptr);
+         break;
+      }
       default:
       {
          VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
diff --git a/CORE/WDI/CP/inc/wlan_qct_wdi.h b/CORE/WDI/CP/inc/wlan_qct_wdi.h
index fd7912b..96bef70 100644
--- a/CORE/WDI/CP/inc/wlan_qct_wdi.h
+++ b/CORE/WDI/CP/inc/wlan_qct_wdi.h
@@ -8647,6 +8647,9 @@
 typedef void (*WDI_AntennaDivSelRspCb)(WDI_Status status,
               void *resp, void *pUserData);
 
+typedef void (*wdi_nud_set_arp_rsp_cb)(void *event_data,void *user_data);
+typedef void (*wdi_nud_get_arp_rsp_cb)(void *event_data,void *user_data);
+
 #ifdef DHCP_SERVER_OFFLOAD
 typedef void (*wdi_dhcp_srv_offload_rsp_cb)(void *event_data,void *user_data);
 #endif /* DHCP_SERVER_OFFLOAD */
@@ -12448,6 +12451,57 @@
 );
 
 void WDI_SetMgmtPktViaWQ5(wpt_boolean sendMgmtPktViaWQ5);
+
+/* ARP DEBUG STATS */
+typedef struct
+{
+   wpt_uint8 flag;
+   wpt_uint8 pkt_type;
+   wpt_uint32 ip_addr;
+} WDI_SetARPStatsParamsInfoType;
+
+typedef struct
+{
+  wpt_uint32 status;
+} WDI_SetARPStatsRspParamsType;
+
+typedef void (*WDI_SetARPStatsRspCb)(WDI_SetARPStatsRspParamsType* StatsRsp,
+                                     void* pUserData);
+
+WDI_Status
+WDI_SetARPStatsReq
+(
+  WDI_SetARPStatsParamsInfoType *pwdiSetStatsReqParams,
+  WDI_SetARPStatsRspCb          wdiSetARPStatsRspCb,
+  void*                      pUserData
+);
+
+/* ARP DEBUG STATS */
+typedef struct
+{
+   wpt_uint8 pkt_type;
+} WDI_GetARPStatsParamsInfoType;
+
+typedef struct
+{
+  wpt_uint32 status;
+  wpt_uint16 dad;
+  wpt_uint16 tx_fw_cnt;
+  wpt_uint16 rx_fw_cnt;
+  wpt_uint16 tx_ack_cnt;
+} WDI_GetARPStatsRspParamsType;
+
+typedef void (*WDI_GetARPStatsRspCb)(WDI_GetARPStatsRspParamsType* StatsRsp,
+                                     void* pUserData);
+
+WDI_Status
+WDI_GetARPStatsReq
+(
+  WDI_GetARPStatsParamsInfoType *pwdiGetStatsReqParams,
+  WDI_GetARPStatsRspCb          wdiGetARPStatsRspCb,
+  void*                      pUserData
+);
+
 WDI_Status
 WDI_process_sap_auth_offload(
    struct WDI_sap_ofl_enable_params *sap_ofl_enable_cmd
diff --git a/CORE/WDI/CP/inc/wlan_qct_wdi_i.h b/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
index 034fe71..a551b7d 100644
--- a/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
+++ b/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
@@ -503,6 +503,10 @@
   WDI_CAP_TSF_REQ                                = 123,
   WDI_GET_TSF_REQ                                = 124,
 
+  /* ARP DEBUG STATS */
+  WDI_FW_ARP_STATS_REQ                           = 125,
+  WDI_FW_GET_ARP_STATS_REQ                       = 126,
+
   WDI_MAX_REQ,
 
   /*Send a suspend Indication down to HAL*/
@@ -889,6 +893,9 @@
   WDI_MDNS_RESP_OFFLOAD_RSP                      = 121,
   WDI_MDNS_STATS_OFFLOAD_RSP                     = 122,
   WDI_CAPTURE_GET_TSF_TSTAMP_RSP                 = 123,
+  WDI_FW_ARP_STATS_RSP                           = 124,
+  WDI_FW_GET_ARP_STATS_RSP                       = 125,
+
 
   /*-------------------------------------------------------------------------
     Indications
@@ -6833,5 +6840,33 @@
     WDI_EventInfoType *event_data
 );
 
+WDI_Status
+WDI_ProcessSetArpStatsReq
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+);
+
+WDI_Status
+WDI_ProcessSetArpStatsResp
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+);
+
+WDI_Status
+WDI_ProcessGetArpStatsReq
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+);
+
+WDI_Status
+WDI_ProcessGetArpStatsResp
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+);
+
 #endif /*WLAN_QCT_WDI_I_H*/
 
diff --git a/CORE/WDI/CP/src/wlan_qct_wdi.c b/CORE/WDI/CP/src/wlan_qct_wdi.c
index 5ed7a7a..5516df0 100644
--- a/CORE/WDI/CP/src/wlan_qct_wdi.c
+++ b/CORE/WDI/CP/src/wlan_qct_wdi.c
@@ -223,6 +223,8 @@
    ,SAP_MODE_WOW                   //64
    ,SAP_OFFLOADS                   //65
    ,SAP_BUFF_ALLOC                 //66
+   ,FEATURE_NOT_SUPPORTED
+   ,NUD_DEBUG                      //68
 };
 
 /*-------------------------------------------------------------------------- 
@@ -538,6 +540,9 @@
   wdi_cap_tsf_req,   /* WDI_CAP_TSF_REQ */
   wdi_get_tsf_req,   /* WDI_GET_TSF_REQ */
 
+  WDI_ProcessSetArpStatsReq,          /* WDI_FW_ARP_STATS_REQ */
+  WDI_ProcessGetArpStatsReq,          /* WDI_FW_GET_ARP_STATS_REQ */
+
   /*-------------------------------------------------------------------------
     Indications
   -------------------------------------------------------------------------*/
@@ -883,6 +888,10 @@
 #endif  /* MDNS_OFFLOAD */
    wdi_get_tsf_rsp, /* WDI_CAPTURE_GET_TSF_TSTAMP_RSP */
 
+   /* ARP Debug Stats*/
+   WDI_ProcessSetArpStatsResp,          /* WDI_FW_ARP_STATS_RSP */
+   WDI_ProcessGetArpStatsResp,          /* WDI_FW_GET_ARP_STATS_RSP */
+
   /*---------------------------------------------------------------------
     Indications
   ---------------------------------------------------------------------*/
@@ -1363,6 +1372,9 @@
 #ifdef WLAN_FEATURE_APFIND
     CASE_RETURN_STRING( WDI_SET_AP_FIND_IND );
 #endif
+    CASE_RETURN_STRING( WDI_FW_ARP_STATS_REQ );
+    CASE_RETURN_STRING( WDI_FW_GET_ARP_STATS_REQ );
+
     default:
         return "Unknown WDI MessageId";
   }
@@ -1566,6 +1578,85 @@
 #endif /* MDNS_OFFLOAD */
 
 /**
+ * WDI_ProcessSetArpStatsResp() - WDI api to process set arp stats response
+ * @wdi_ctx: wdi context
+ * @event_data: event data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_ProcessSetArpStatsResp
+(
+    WDI_ControlBlockType *wdi_ctx,
+    WDI_EventInfoType *event_data
+)
+{
+    wdi_nud_set_arp_rsp_cb nud_set_arp_rsp_callback;
+
+    WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
+               "%s: Enter ", __func__);
+       /*-------------------------------------------------------------------
+         Sanity check
+         -----------------------------------------------------------------*/
+    if ((NULL == wdi_ctx) || (NULL == event_data) ||
+        (NULL == event_data->pEventData))
+    {
+         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+                    "%s: Invalid parameters", __func__);
+         WDI_ASSERT(0);
+        return WDI_STATUS_E_FAILURE;
+    }
+
+    nud_set_arp_rsp_callback =
+            (wdi_nud_set_arp_rsp_cb)wdi_ctx->pfncRspCB;
+
+    nud_set_arp_rsp_callback((void *) event_data->pEventData,
+                                      wdi_ctx->pRspCBUserData);
+
+    return WDI_STATUS_SUCCESS;
+}
+
+/**
+ * WDI_ProcessGetArpStatsResp() - WDI api to process get arp stats response
+ * @wdi_ctx: wdi context
+ * @event_data: event data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_ProcessGetArpStatsResp
+(
+    WDI_ControlBlockType *wdi_ctx,
+    WDI_EventInfoType *event_data
+)
+{
+    wdi_nud_get_arp_rsp_cb nud_get_arp_rsp_callback;
+
+    WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
+               "%s: Enter ", __func__);
+    /*-------------------------------------------------------------------
+      Sanity check
+     -----------------------------------------------------------------*/
+    if ((NULL == wdi_ctx) || (NULL == event_data) ||
+        (NULL == event_data->pEventData))
+    {
+        WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+                   "%s: Invalid parameters", __func__);
+        WDI_ASSERT(0);
+        return WDI_STATUS_E_FAILURE;
+    }
+
+    nud_get_arp_rsp_callback =
+        (wdi_nud_get_arp_rsp_cb)wdi_ctx->pfncRspCB;
+
+    nud_get_arp_rsp_callback((void *) event_data->pEventData,
+        wdi_ctx->pRspCBUserData);
+
+    return WDI_STATUS_SUCCESS;
+}
+
+
+/**
  @brief WDI_getRespMsgString prints the WDI resonse message in string.
 
  @param wdiRespMsgId: WDI Message response Id
@@ -1922,6 +2013,11 @@
                                          "%s", "SAP_BUFF_ALLOC");
                           pCapStr += strlen("SAP_BUFF_ALLOC");
                           break;
+                     case NUD_DEBUG:
+                          snprintf(pCapStr, sizeof("NUD_DEBUG"),
+                                         "%s", "NUD_DEBUG");
+                          pCapStr += strlen("NUD_DEEBUG");
+                          break;
                  }
                  *pCapStr++ = ',';
                  *pCapStr++ = ' ';
@@ -25050,6 +25146,10 @@
      return WLAN_HAL_CAPTURE_GET_TSF_TSTAMP;
   case WDI_GET_TSF_REQ:
      return WLAN_HAL_CAPTURE_GET_TSF_TSTAMP;
+  case WDI_FW_ARP_STATS_REQ:
+      return WLAN_HAL_FW_SET_CLEAR_ARP_STATS_REQ;
+  case WDI_FW_GET_ARP_STATS_REQ:
+      return WLAN_HAL_FW_GET_ARP_STATS_REQ;
   default:
     return WLAN_HAL_MSG_MAX;
   }
@@ -25439,6 +25539,10 @@
 #endif
   case WLAN_HAL_CAPTURE_GET_TSF_TSTAMP_RSP:
     return WDI_CAPTURE_GET_TSF_TSTAMP_RSP;
+  case WLAN_HAL_FW_SET_CLEAR_ARP_STATS_RSP:
+       return WDI_FW_ARP_STATS_RSP;
+  case WLAN_HAL_FW_GET_ARP_STATS_RSP:
+       return WDI_FW_GET_ARP_STATS_RSP;
   default:
     return eDRIVER_TYPE_MAX;
   }
@@ -39302,6 +39406,216 @@
 
     return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData);
 }
+
+/**
+ * WDI_ProcessSetArpStatsReq() - WDI api to process arp stats request
+ * @pWDICtx: wdi context
+ * @pEventData: event data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_ProcessSetArpStatsReq
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+)
+{
+   WDI_SetARPStatsParamsInfoType  *pSetARPStatsReqParams;
+   WDI_SetARPStatsRspCb  wdiSetARPStatsRspCb;
+   wpt_uint8*            pSendBuffer;
+   wpt_uint16            usDataOffset;
+   wpt_uint16            usSendSize;
+   WDI_Status wdi_status;
+   tHalStatsArpReqMsg statsReqParams;
+
+   VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
+             "%s: %d Enter",__func__, __LINE__);
+
+  if (( NULL == pEventData ) || ( NULL == pEventData->pEventData) ||
+      ( NULL == pWDICtx ) )
+  {
+     WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+                 "%s: Invalid parameters", __func__);
+     WDI_ASSERT(0);
+     return WDI_STATUS_E_FAILURE;
+  }
+
+  pSetARPStatsReqParams =
+       (WDI_SetARPStatsParamsInfoType *)pEventData->pEventData;
+  wdiSetARPStatsRspCb   = (WDI_SetARPStatsRspCb)pEventData->pCBfnc;
+
+  if ((WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx, WDI_FW_ARP_STATS_REQ,
+                        sizeof(statsReqParams.statsArpReqParams),
+                        &pSendBuffer, &usDataOffset, &usSendSize))||
+      ( usSendSize < (usDataOffset + sizeof(statsReqParams.statsArpReqParams))))
+  {
+     WPAL_TRACE( eWLAN_MODULE_DAL_CTRL,  eWLAN_PAL_TRACE_LEVEL_WARN,
+              "Unable to get send buffer in set bss key req %p %p %p",
+                pEventData, pSetARPStatsReqParams, wdiSetARPStatsRspCb);
+     WDI_ASSERT(0);
+     return WDI_STATUS_E_FAILURE;
+  }
+
+  statsReqParams.statsArpReqParams.set_clr = pSetARPStatsReqParams->flag;
+  statsReqParams.statsArpReqParams.pkt_type =
+                      pSetARPStatsReqParams->pkt_type;
+  statsReqParams.statsArpReqParams.ip_addr = pSetARPStatsReqParams->ip_addr;
+
+  wpalMemoryCopy( pSendBuffer+usDataOffset,
+                  &statsReqParams.statsArpReqParams,
+                  sizeof(statsReqParams.statsArpReqParams));
+
+  wdi_status = WDI_SendMsg(pWDICtx, pSendBuffer, usSendSize,
+                      wdiSetARPStatsRspCb, pEventData->pUserData,
+                      WDI_FW_ARP_STATS_RSP);
+
+  VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
+            "%s: %d Exit",__func__, __LINE__);
+  return wdi_status;
+}
+
+/**
+ * WDI_SetARPStatsReq() - WDI api to process set arp stats request
+ * @pwdiSetStatsReqParams: pointer to set stats params
+ * @wdiSetStatsRspCb: pointer to set response callback
+ * @pUserData: user data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_SetARPStatsReq
+(
+  WDI_SetARPStatsParamsInfoType* pwdiSetStatsReqParams,
+  WDI_SetARPStatsRspCb          wdiSetStatsRspCb,
+  void*                      pUserData
+)
+{
+  WDI_EventInfoType      wdiEventData;
+
+  if (eWLAN_PAL_FALSE == gWDIInitialized )
+  {
+    WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
+              "WDI API call before module is initialized - Fail request");
+
+    return WDI_STATUS_E_NOT_ALLOWED;
+  }
+
+  wdiEventData.wdiRequest      = WDI_FW_ARP_STATS_REQ;
+  wdiEventData.pEventData      = pwdiSetStatsReqParams;
+  wdiEventData.uEventDataSize  = sizeof(*pwdiSetStatsReqParams);
+  wdiEventData.pCBfnc          = wdiSetStatsRspCb;
+  wdiEventData.pUserData       = pUserData;
+
+  return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData);
+
+}/*WDI_GetARPStatsReq*/
+
+/**
+ * WDI_ProcessGetArpStatsReq() - WDI api to process get arp stats request
+ * @pWDICtx: wdi context
+ * @pEventData: event data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_ProcessGetArpStatsReq
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+)
+{
+   WDI_GetARPStatsParamsInfoType  *pGetARPStatsReqParams;
+   WDI_GetARPStatsRspCb  wdiGetARPStatsRspCb;
+   wpt_uint8*            pSendBuffer;
+   wpt_uint16            usDataOffset;
+   wpt_uint16            usSendSize;
+   WDI_Status wdi_status;
+   tHalStatsGetArpReqMsg statsReqParams;
+
+   VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
+             "%s: %d Enter",__func__, __LINE__);
+
+  if (( NULL == pEventData ) || ( NULL == pEventData->pEventData) ||
+      ( NULL == pWDICtx ) )
+  {
+     WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+                 "%s: Invalid parameters", __func__);
+     WDI_ASSERT(0);
+     return WDI_STATUS_E_FAILURE;
+  }
+
+  pGetARPStatsReqParams =
+     (WDI_GetARPStatsParamsInfoType *)pEventData->pEventData;
+  wdiGetARPStatsRspCb   = (WDI_GetARPStatsRspCb)pEventData->pCBfnc;
+
+  if ((WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx,
+                        WDI_FW_GET_ARP_STATS_REQ,
+                        sizeof(statsReqParams.statsGetArpReqParams),
+                        &pSendBuffer, &usDataOffset, &usSendSize))||
+      ( usSendSize < (usDataOffset +
+                      sizeof(statsReqParams.statsGetArpReqParams))))
+  {
+     WPAL_TRACE( eWLAN_MODULE_DAL_CTRL,  eWLAN_PAL_TRACE_LEVEL_WARN,
+              "Unable to get send buffer in set bss key req %p %p %p",
+                pEventData, pGetARPStatsReqParams, wdiGetARPStatsRspCb);
+     WDI_ASSERT(0);
+     return WDI_STATUS_E_FAILURE;
+  }
+
+  statsReqParams.statsGetArpReqParams.pkt_type =
+                      pGetARPStatsReqParams->pkt_type;
+
+  wpalMemoryCopy( pSendBuffer+usDataOffset,
+                  &statsReqParams.statsGetArpReqParams,
+                  sizeof(statsReqParams.statsGetArpReqParams));
+
+  wdi_status = WDI_SendMsg(pWDICtx, pSendBuffer, usSendSize,
+                      wdiGetARPStatsRspCb, pEventData->pUserData,
+                      WDI_FW_GET_ARP_STATS_RSP);
+
+  VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
+            "%s: %d Exit",__func__, __LINE__);
+  return wdi_status;
+}
+
+/**
+ * WDI_GetARPStatsReq() - WDI api to process get arp stats request
+ * @pwdiGetStatsReqParams: pointer to get stats params
+ * @wdiGetStatsRspCb: pointer to get response callback
+ * @pUserData: user data
+ *
+ * Return: WDI_Status
+ */
+WDI_Status
+WDI_GetARPStatsReq
+(
+  WDI_GetARPStatsParamsInfoType* pwdiGetStatsReqParams,
+  WDI_GetARPStatsRspCb          wdiGetStatsRspCb,
+  void*                      pUserData
+)
+{
+  WDI_EventInfoType      wdiEventData;
+
+  if (eWLAN_PAL_FALSE == gWDIInitialized )
+  {
+    WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
+              "WDI API call before module is initialized - Fail request");
+
+    return WDI_STATUS_E_NOT_ALLOWED;
+  }
+
+  wdiEventData.wdiRequest      = WDI_FW_GET_ARP_STATS_REQ;
+  wdiEventData.pEventData      = pwdiGetStatsReqParams;
+  wdiEventData.uEventDataSize  = sizeof(*pwdiGetStatsReqParams);
+  wdiEventData.pCBfnc          = wdiGetStatsRspCb;
+  wdiEventData.pUserData       = pUserData;
+
+  return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData);
+
+}/*WDI_GetARPStatsReq*/
+
+
 #ifdef SAP_AUTH_OFFLOAD
 /**
  *  WDI_ProcessSapAuthOffloadInd() - Process SAP AUTH ofload