wlan: During ARP debug set FW in datapath for ARP

For ARP packet debug keep FW in datapath and set tx BD complete
Tx interrupt field with dialogue token. Also Make use of reserved
TX BD field to indicate packet as ARP to FW.

Change-Id: I8477388ecc83bf6e9dfa75d85d5c8dcbb9f774d7
CRs-Fixed: 1115218
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index ad84c95..8495e49 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -1795,6 +1795,8 @@
     scan_reject_states last_scan_reject_reason;
     v_TIME_t last_scan_reject_timestamp;
     bool is_ap_mode_wow_supported;
+
+    uint32_t track_arp_ip;
 };
 
 typedef enum  {
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index fa56021..7bc99e3 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -7586,6 +7586,7 @@
     struct net_device   *dev = wdev->netdev;
     hdd_adapter_t       *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
     hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+    v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(adapter))->pvosContext;
     setArpStatsParams arp_stats_params;
     int err = 0;
 
@@ -7630,6 +7631,19 @@
 
     arp_stats_params.pkt_type = 1; // ARP packet type
 
+    if (arp_stats_params.flag) {
+       hdd_ctx->track_arp_ip = arp_stats_params.ip_addr;
+       WLANTL_SetARPFWDatapath(pVosContext, true);
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                 "%s Set FW in data path for ARP with tgt IP :%d",
+                 __func__,  hdd_ctx->track_arp_ip);
+    }
+    else {
+       WLANTL_SetARPFWDatapath(pVosContext, false);
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                 "%s Remove FW from data path", __func__);
+    }
+
     arp_stats_params.rsp_cb_fn = hdd_set_nud_stats_cb;
     arp_stats_params.data_ctx = adapter;
 
diff --git a/CORE/TL/inc/wlan_qct_tl.h b/CORE/TL/inc/wlan_qct_tl.h
index 631be11..45f3b9d 100644
--- a/CORE/TL/inc/wlan_qct_tl.h
+++ b/CORE/TL/inc/wlan_qct_tl.h
@@ -3419,4 +3419,12 @@
 void WLANTL_RegisterFwdEapol(v_PVOID_t pvosGCtx,
                              WLANTL_FwdEapolCBType pfnFwdEapol);
 
+/**
+ * WLANTL_SetARPFWDatapath() - keep or remove FW in data path for ARP
+ * @pvosGCtx: global vos context
+ * @flag: value to keep or remove FW from data path
+ *
+ * Return: void
+ */
+void WLANTL_SetARPFWDatapath(void * pvosGCtx, bool flag);
 #endif /* #ifndef WLAN_QCT_WLANTL_H */
diff --git a/CORE/TL/src/wlan_qct_tl.c b/CORE/TL/src/wlan_qct_tl.c
index 4e7ad14..e5786c0 100755
--- a/CORE/TL/src/wlan_qct_tl.c
+++ b/CORE/TL/src/wlan_qct_tl.c
@@ -2775,8 +2775,8 @@
                     ucWDSEnabled, extraHeadSpace, pMetaInfo->ucType,
                             &pTLCb->atlSTAClients[ucStaId]->wSTADesc.vSelfMACAddress,
                     pMetaInfo->ucTID, 0 /* No ACK */, pMetaInfo->usTimeStamp,
-                    pMetaInfo->ucIsEapol || pMetaInfo->ucIsWai, pMetaInfo->ucUP,
-                    pMetaInfo->ucTxBdToken);
+                    pMetaInfo->ucIsEapol || pMetaInfo->ucIsWai, pMetaInfo->ucIsArp,
+                    pMetaInfo->ucUP, pMetaInfo->ucTxBdToken);
 
   if ( VOS_STATUS_SUCCESS != vosStatus )
   {
@@ -3717,7 +3717,7 @@
     vosStatus = WDA_DS_BuildTxPacketInfo( pvosGCtx, vosFrmBuf , &vDestMacAddr, 
                    1 /* always 802.11 frames*/, &usPktLen, uQosHdr /*qos not enabled !!!*/, 
                    0 /* WDS off */, 0, wFrmType, pvAddr2MacAddr, ucTid,
-                   ucAckResponse, usTimeStamp, 0, 0, ucTxBdToken);
+                   ucAckResponse, usTimeStamp, 0, 0, 0, ucTxBdToken);
 
 
     if ( !VOS_IS_STATUS_SUCCESS(vosStatus) )
@@ -8132,8 +8132,8 @@
                           extraHeadSpace,
                           ucTypeSubtype, &pClientSTA->wSTADesc.vSelfMACAddress,
                           ucTid, txFlag,
-                          tlMetaInfo.usTimeStamp, tlMetaInfo.ucIsEapol || tlMetaInfo.ucIsWai, tlMetaInfo.ucUP,
-                          tlMetaInfo.ucTxBdToken);
+                          tlMetaInfo.usTimeStamp, tlMetaInfo.ucIsEapol || tlMetaInfo.ucIsWai,
+                          tlMetaInfo.ucIsArp, tlMetaInfo.ucUP, tlMetaInfo.ucTxBdToken);
 
   if ( VOS_STATUS_SUCCESS != vosStatus )
   {
@@ -8552,6 +8552,16 @@
 #endif /* FEATURE_WLAN_TDLS */
   if( tlMetaInfo.ucIsArp )
   {
+    if (pTLCb->track_arp)
+    {
+       if (vos_check_arp_target_ip(vosDataBuff))
+       {
+          ucTxFlag |= HAL_USE_FW_IN_TX_PATH;
+          ucTxFlag |= HAL_TXCOMP_REQUESTED_MASK;
+          tlMetaInfo.ucTxBdToken = ++ pTLCb->txbd_token;
+       }
+    }
+
     if (pStaClient->arpOnWQ5)
     {
         ucTxFlag |= HAL_USE_FW_IN_TX_PATH;
@@ -8576,7 +8586,7 @@
                      extraHeadSpace,
                      ucTypeSubtype, &pStaClient->wSTADesc.vSelfMACAddress,
                      ucTid, ucTxFlag, tlMetaInfo.usTimeStamp, 
-                     tlMetaInfo.ucIsEapol, tlMetaInfo.ucUP,
+                     tlMetaInfo.ucIsEapol, tlMetaInfo.ucIsArp, tlMetaInfo.ucUP,
                      tlMetaInfo.ucTxBdToken);
 
   if(!VOS_IS_STATUS_SUCCESS(vosStatus))
@@ -14345,6 +14355,29 @@
 
 }
 
+ /**
+ * WLANTL_SetARPFWDatapath() - keep or remove FW in data path for ARP
+ *
+ * @flag: value to keep or remove FW from data path
+ *
+ * Return: void
+ */
+void WLANTL_SetARPFWDatapath(void * pvosGCtx, bool flag)
+{
+
+   WLANTL_CbType*  pTLCb = NULL;
+
+   pTLCb = VOS_GET_TL_CB(pvosGCtx);
+   if (NULL == pTLCb) {
+      TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+             "%s: Invalid TL pointer from pvosGCtx", __func__));
+      return;
+   }
+
+   pTLCb->track_arp = flag;
+
+}
+
 #ifdef WLAN_FEATURE_RMC
 VOS_STATUS WLANTL_RmcInit
 (
diff --git a/CORE/TL/src/wlan_qct_tli.h b/CORE/TL/src/wlan_qct_tli.h
index 1ea05be..cb6414a 100644
--- a/CORE/TL/src/wlan_qct_tli.h
+++ b/CORE/TL/src/wlan_qct_tli.h
@@ -1006,6 +1006,10 @@
   bool preassoc_caching;
   vos_pkt_t* vosEapolCachedFrame;
   WLANTL_FwdEapolCBType pfnEapolFwd;
+
+  uint8_t track_arp;
+  uint32_t txbd_token;
+
 }WLANTL_CbType;
 
 
diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h
index 00c1817..abcef0a 100644
--- a/CORE/VOSS/inc/vos_api.h
+++ b/CORE/VOSS/inc/vos_api.h
@@ -530,4 +530,6 @@
 void vos_smd_dump_stats(void);
 void vos_log_wdi_event(uint16 msg, vos_wdi_trace_event_type event);
 void vos_dump_wdi_events(void);
+
+bool vos_check_arp_target_ip(vos_pkt_t *pPacket);
 #endif // if !defined __VOS_NVITEM_H
diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c
index 814c113..68e93f8 100644
--- a/CORE/VOSS/src/vos_api.c
+++ b/CORE/VOSS/src/vos_api.c
@@ -103,6 +103,9 @@
 /* Trace index for WDI Read/Write */
 #define VOS_TRACE_INDEX_MAX 256
 
+/* ARP Target IP offset */
+#define VOS_ARP_TARGET_IP_OFFSET 58
+
 /*---------------------------------------------------------------------------
  * Data definitions
  * ------------------------------------------------------------------------*/
@@ -3759,3 +3762,50 @@
             gvos_wdi_msg_trace[i].message);
   }
 }
+
+/**
+ * vos_check_arp_target_ip() - check if the Target IP is gateway IP
+ * @pPacket: pointer to vos packet
+ *
+ * Return: true if the IP is of gateway or false otherwise
+ */
+bool vos_check_arp_target_ip(vos_pkt_t *pPacket)
+{
+   v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+   hdd_context_t *pHddCtx = NULL;
+   struct sk_buff *skb;
+
+   if(!pVosContext)
+   {
+      hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
+      return false;
+   }
+
+   pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
+   if(!pHddCtx) {
+      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+               "%s: HDD context is Null", __func__);
+      return false;
+   }
+
+   if (unlikely(NULL == pPacket))
+   {
+      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+                "%s: NULL pointer", __func__);
+      return false;
+   }
+
+   if ( VOS_STATUS_SUCCESS !=
+        vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE ))
+   {
+      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+                "%s: OS PKT pointer is NULL", __func__);
+      return false;
+   }
+
+   if (pHddCtx->track_arp_ip ==
+       (v_U32_t)(*(v_U32_t *)(skb->data + VOS_ARP_TARGET_IP_OFFSET)))
+      return true;
+
+   return false;
+}
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index 70c8d1d..997c80d 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -1634,6 +1634,7 @@
     txFlag
     timeStamp
     ucIsEapol
+    ucIsArp
     ucUP
 
    OUT
@@ -1663,6 +1664,7 @@
   v_U32_t          txFlag,
   v_U32_t         timeStamp,
   v_U8_t          ucIsEapol,
+  v_U8_t          ucIsArp,
   v_U8_t          ucUP,
   v_U32_t         ucTxBdToken
 );
diff --git a/CORE/WDA/src/wlan_qct_wda_ds.c b/CORE/WDA/src/wlan_qct_wda_ds.c
index 2e303fb..b4a9bbb 100644
--- a/CORE/WDA/src/wlan_qct_wda_ds.c
+++ b/CORE/WDA/src/wlan_qct_wda_ds.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -436,6 +436,7 @@
   v_U32_t          txFlag,
   v_U32_t         timeStamp,
   v_U8_t          ucIsEapol,
+  v_U8_t          ucIsArp,
   v_U8_t          ucUP,
   v_U32_t         ucTxBdToken
 )
@@ -497,6 +498,7 @@
   pTxMetaInfo->ac         = ucUP;
   pTxMetaInfo->fUP        = uTid;
   pTxMetaInfo->isEapol    = ucIsEapol;
+  pTxMetaInfo->isArp      = ucIsArp;
   pTxMetaInfo->fdisableFrmXlt = ucDisableFrmXtl;
   pTxMetaInfo->frmType     = ( ( typeSubtype & 0x30 ) >> 4 );
   pTxMetaInfo->typeSubtype = typeSubtype;
diff --git a/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h b/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h
index 0e9faa6..4ca3a65 100644
--- a/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h
+++ b/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1120,10 +1120,13 @@
         This is filled by Host in Virgo 1.0 but it gets filled by ADU in
         Virgo2.0/Libra. Queue ID */
         wpt_uint32 queueId:5;
-    
-        wpt_uint32 reserved5:7;
+
+        wpt_uint32 isArp:1;
+
+        wpt_uint32 reserved5:6;
 #else
-        wpt_uint32 reserved5:7;
+        wpt_uint32 reserved5:6;
+        wpt_uint32 isArp:1;
         wpt_uint32 queueId:5;
         wpt_uint32 bdRate:2;
         wpt_uint32 ap:2;
diff --git a/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h b/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
index e7c0dac..ca1b403 100644
--- a/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
+++ b/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -439,6 +439,7 @@
     wpt_uint8              ucProtMgmtFrame,
     wpt_uint32             uTimeStamp,
     wpt_uint8              isEapol,
+    wpt_uint8              isArp,
     wpt_uint8*             staIndex,
     wpt_uint32             txBdToken
 );
diff --git a/CORE/WDI/CP/src/wlan_qct_wdi_dp.c b/CORE/WDI/CP/src/wlan_qct_wdi_dp.c
index 48bf139..25d627f 100644
--- a/CORE/WDI/CP/src/wlan_qct_wdi_dp.c
+++ b/CORE/WDI/CP/src/wlan_qct_wdi_dp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -386,6 +386,7 @@
     wpt_uint8              ucProtMgmtFrame,
     wpt_uint32             uTimeStamp,
     wpt_uint8              isEapol,
+    wpt_uint8              isArp,
     wpt_uint8*             staIndex,
     wpt_uint32             txBdToken
 )
@@ -409,6 +410,9 @@
        Get type and subtype of the frame first 
     ------------------------------------------------------------------------*/
     pBd->txBdToken = txBdToken;
+
+    pBd->isArp = isArp;
+
     ucType = (ucTypeSubtype & WDI_FRAME_TYPE_MASK) >> WDI_FRAME_TYPE_OFFSET;
     ucSubType = (ucTypeSubtype & WDI_FRAME_SUBTYPE_MASK);
 
diff --git a/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h b/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h
index e3be91a..4f88b99 100644
--- a/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h
+++ b/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -53,11 +53,12 @@
    wpt_uint32 txFlags;
    wpt_uint8 ac;
    wpt_uint8 isEapol:1; //0 - not eapol 1 - eapol
-   wpt_uint8 isWai:1;   //WAPI 0 - not WAI 1 WAI 
+   wpt_uint8 isWai:1;   //WAPI 0 - not WAI 1 WAI
+   wpt_uint8 isArp:1;   //0 - not ARP 1 - ARP
    wpt_uint8 fdisableFrmXlt:1;   //0 - Let ADU do FT. 1 - bypass ADU FT
    wpt_uint8 qosEnabled:1; //0 - non-Qos 1 - Qos
    wpt_uint8 fenableWDS:1; //0 - not WDS 1 WDS
-   wpt_uint8 reserved1:3;
+   wpt_uint8 reserved1:2;
    wpt_uint8 typeSubtype;
    wpt_uint8 fUP;
    wpt_uint8 fSTAMACAddress[6];
diff --git a/CORE/WDI/DP/src/wlan_qct_wdi_ds.c b/CORE/WDI/DP/src/wlan_qct_wdi_ds.c
index 902c0de..e0f2c53 100644
--- a/CORE/WDI/DP/src/wlan_qct_wdi_ds.c
+++ b/CORE/WDI/DP/src/wlan_qct_wdi_ds.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -129,6 +129,7 @@
   wpt_uint8      ucUP;
   wpt_uint8      ucTypeSubtype;
   wpt_uint8      isEapol;
+  wpt_uint8      isArp;
   wpt_uint8      alignment;
   wpt_uint32     ucTxFlag;
   wpt_uint8      ucProtMgmtFrame;
@@ -160,6 +161,7 @@
   ucTypeSubtype = pTxMetadata->typeSubtype;
   ucUP = pTxMetadata->fUP;
   isEapol = pTxMetadata->isEapol;
+  isArp = pTxMetadata->isArp;
   ucTxFlag = pTxMetadata->txFlags;
   ucProtMgmtFrame = pTxMetadata->fProtMgmtFrame;
   pSTAMACAddress = &(pTxMetadata->fSTAMACAddress[0]);
@@ -212,8 +214,8 @@
               "Packet Length is %d\n", pTxMetadata->fPktlen);
   }
   wdiStatus = WDI_FillTxBd(pContext, ucTypeSubtype, pSTAMACAddress, pAddr2MACAddress,
-    &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, ucProtMgmtFrame, 0, isEapol, &staId,
-    pTxMetadata->txBdToken);
+    &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, ucProtMgmtFrame, 0, isEapol, isArp,
+    &staId, pTxMetadata->txBdToken);
 
   if(WDI_STATUS_SUCCESS != wdiStatus)
   {