wlan: Fix reorder packets PN replay check algorithm

Currently for reorder packets PN replay check of the out
of order missing packet is done with the last packet received
in the reorder window slot. The PN number of the out of order
missing packet will be less than the last received packet in
the window and packet drop happens because of replay check.

In this change fix the logic by doing the replay check of the
out of order missing packet with the previous sequence packet
that of out of order packet.

Change-Id: Ib83b825d4b9b292e125c98d819fdfa6eb160e389
CRs-Fixed: 2145435
diff --git a/CORE/TL/src/wlan_qct_tl.c b/CORE/TL/src/wlan_qct_tl.c
old mode 100755
new mode 100644
index 97e4766..07ff758
--- a/CORE/TL/src/wlan_qct_tl.c
+++ b/CORE/TL/src/wlan_qct_tl.c
@@ -6225,6 +6225,7 @@
 #endif
   uint8_t            ucMPDUHLen;
   uint16_t           seq_no;
+  u64                pn_num;
   uint16_t           usEtherType = 0;
 
   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
@@ -6411,6 +6412,9 @@
       uDPUSig = WDA_GET_RX_DPUSIG(pvBDHeader);
       ucMPDUHLen = (uint8_t)WDA_GET_RX_MPDU_HEADER_LEN(pvBDHeader);
       seq_no = (uint16_t)WDA_GET_RX_REORDER_CUR_PKT_SEQ_NO(pvBDHeader);
+      pn_num = WDA_GET_RX_REPLAY_COUNT(pvBDHeader);
+
+      vosTempBuff->pn_num = pn_num;
 
       TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
                  "WLAN TL:Data packet received for STA %d", ucSTAId));
@@ -9696,7 +9700,8 @@
     WLANTL_MSDUReorder( pTLCb, &vosDataBuff, aucBDHeader, ucSTAId, ucTid );
   }
 
-if(0 == ucUnicastBroadcastType
+if(WLANTL_IS_DATA_FRAME(WDA_GET_RX_TYPE_SUBTYPE(aucBDHeader)) &&
+   (0 == ucUnicastBroadcastType)
 #ifdef FEATURE_ON_CHIP_REORDERING
    && (WLANHAL_IsOnChipReorderingEnabledForTID(pvosGCtx, ucSTAId, ucTid) != TRUE)
 #endif
@@ -9773,30 +9778,36 @@
 
            /* It is not AMSDU frame so perform 
               reaply check for each packet, as
-              each packet contains valid replay counter*/ 
-           status =  WLANTL_IsReplayPacket( ullcurrentReplayCounter, ullpreviousReplayCounter);
-           if(VOS_FALSE == status)
-           {
-                /* Not a replay paket, update previous replay counter in TL CB */    
-                pClientSTA->ullReplayCounter[ucTid] = ullcurrentReplayCounter;
-           }
-           else
-           {
-              VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
-               "WLAN TL: Non-AMSDU Drop the replay packet with PN : [0x%llX]",ullcurrentReplayCounter);
+              each packet contains valid replay counter*/
+           if (vosDataBuff != NULL) {
+              if (vos_is_pkt_chain(vosDataBuff)) {
+                 WLANTL_ReorderReplayCheck(pClientSTA, &vosDataBuff, ucTid);
+              } else {
+                 status =  WLANTL_IsReplayPacket(ullcurrentReplayCounter,
+                                                 ullpreviousReplayCounter);
+                 if(VOS_FALSE == status) {
+                    /* Not a replay paket, update previous replay counter in TL CB */
+                    pClientSTA->ullReplayCounter[ucTid] = ullcurrentReplayCounter;
+                 } else {
+                    VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                    "WLAN TL: Non AMSDU Drop replay packet with PN: [0x%llX], prevPN: [0x%llx]",
+                    ullcurrentReplayCounter, ullpreviousReplayCounter);
 
-               pClientSTA->ulTotalReplayPacketsDetected++;
-               VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
-                "WLAN TL: Non-AMSDU total dropped replay packets on STA ID %X is [0x%X]",
-                ucSTAId, pClientSTA->ulTotalReplayPacketsDetected);
+                    pClientSTA->ulTotalReplayPacketsDetected++;
+                    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                    "WLAN TL: Non AMSDU total dropped replay packets on STA ID %X is [0x%X]",
+                    ucSTAId,  pClientSTA->ulTotalReplayPacketsDetected);
 
-               /* Repaly packet, drop the packet */
-               vos_pkt_return_packet(vosDataBuff);
-               return VOS_STATUS_SUCCESS;
-           }
+                    /* Repaly packet, drop the packet */
+                    vos_pkt_return_packet(vosDataBuff);
+                    return VOS_STATUS_SUCCESS;
+                 }
+              }
+          }
       }
-  }
+   }
 }
+
 /*It is a broadast packet DPU has already done replay check for 
   broadcast packets no need to do replay check of these packets*/
 
diff --git a/CORE/TL/src/wlan_qct_tl_ba.c b/CORE/TL/src/wlan_qct_tl_ba.c
index e01d128..166e6d6 100644
--- a/CORE/TL/src/wlan_qct_tl_ba.c
+++ b/CORE/TL/src/wlan_qct_tl_ba.c
@@ -220,66 +220,6 @@
       fwIdx = ReorderInfo->ucCIndex - 1;
    }
 
-   /* Do replay check before giving packets to upper layer 
-      replay check code : check whether replay check is needed or not */
-   if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid)
-   {
-       v_U64_t    ullpreviousReplayCounter = 0;
-       v_U64_t    ullcurrentReplayCounter = 0;
-       v_U8_t     ucloopCounter = 0;
-       v_BOOL_t   status = 0;
-
-       /*Do replay check for all packets which are in Reorder buffer */
-       for(ucloopCounter = 0; ucloopCounter < WLANTL_MAX_WINSIZE; ucloopCounter++)
-       {
-         /*Get previous reply counter*/
-         ullpreviousReplayCounter = pClientSTA->ullReplayCounter[ucTID];
-
-         /*Get current replay counter of packet in reorder buffer*/
-         ullcurrentReplayCounter = ReorderInfo->reorderBuffer->ullReplayCounter[ucloopCounter];
-
-         /*Check for holes, if a hole is found in Reorder buffer then
-           no need to do replay check on it, skip the current
-           hole and do replay check on other packets*/
-         if(NULL != (ReorderInfo->reorderBuffer->arrayBuffer[ucloopCounter]))
-         {
-           status = WLANTL_IsReplayPacket(ullcurrentReplayCounter, ullpreviousReplayCounter); 
-           if(VOS_TRUE == status)
-           {
-               /*Increment the debug counter*/
-               pClientSTA->ulTotalReplayPacketsDetected++;
-
-               /*A replay packet found*/
-               VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
-                "WLANTL_ReorderingAgingTimerExpierCB: total dropped replay packets on STA ID %X is [0x%X]",
-                ucSTAID, pClientSTA->ulTotalReplayPacketsDetected);
-
-               VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
-                "WLANTL_ReorderingAgingTimerExpierCB: replay packet found with PN : [0x%llX]",
-                ullcurrentReplayCounter);
-
-               VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
-                "WLANTL_ReorderingAgingTimerExpierCB: Drop the replay packet with PN : [0x%llX]",
-                ullcurrentReplayCounter);
-
-               ReorderInfo->reorderBuffer->arrayBuffer[ucloopCounter] = NULL;
-               ReorderInfo->reorderBuffer->ullReplayCounter[ucloopCounter] = 0;
-           }
-           else
-           {
-              /*Not a replay packet update previous replay counter*/
-              pClientSTA->ullReplayCounter[ucTID] = ullcurrentReplayCounter;
-           }
-         }
-         else
-         {
-              /* A hole detected in Reorder buffer*/
-              //BAMSGERROR("WLANTL_ReorderingAgingTimerExpierCB,hole detected\n",0,0,0);
-               
-         }
-       } 
-   }
-
    cIndex = ReorderInfo->ucCIndex;
    status = WLANTL_ChainFrontPkts(fwIdx, opCode, 
                                   &vosDataBuff, ReorderInfo, NULL);
@@ -314,6 +254,12 @@
       return;
    }
 
+   /* Do replay check before giving packets to upper layer
+      replay check code : check whether replay check is needed or not */
+   if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid) {
+      WLANTL_ReorderReplayCheck(pClientSTA, &vosDataBuff, ucTID);
+   }
+
    pCurrent = vosDataBuff;
 
    while (pCurrent != NULL)
@@ -755,6 +701,12 @@
              "WLAN TL: Chaining was successful sending all pkts to HDD : %x",
               vosDataBuff ));
 
+    /* Do replay check before giving packets to upper layer
+       replay check code : check whether replay check is needed or not */
+    if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid) {
+      WLANTL_ReorderReplayCheck(pClientSTA, &vosDataBuff, ucTid);
+    }
+
     if ( WLAN_STA_SOFTAP == pClientSTA->wSTADesc.wSTAType )
     {
       WLANTL_FwdPktToHDD( pvosGCtx, vosDataBuff, ucSTAId);
@@ -1923,3 +1875,44 @@
    return;
 }/*WLANTL_FillReplayCounter*/
 
+void WLANTL_ReorderReplayCheck(WLANTL_STAClientType *pClientSTA,
+                               vos_pkt_t **vosDataBuff, v_U8_t ucTid)
+{
+   vos_pkt_t *pVosCurPkt;
+   vos_pkt_t *pNextVosPkt;
+   vos_pkt_t *pVosHeadPkt = NULL;
+   vos_pkt_t *pfreeVosPkt = NULL;
+   v_U64_t   prevReplayCounter = 0;
+   v_BOOL_t status;
+
+   pVosCurPkt = *vosDataBuff;
+
+   do {
+      vos_pkt_walk_packet_chain(pVosCurPkt, &pNextVosPkt, VOS_FALSE);
+      prevReplayCounter = pClientSTA->ullReplayCounter[ucTid];
+      status =  WLANTL_IsReplayPacket(pVosCurPkt->pn_num,
+                                      prevReplayCounter);
+      if(VOS_FALSE == status) {
+         pClientSTA->ullReplayCounter[ucTid] = pVosCurPkt->pn_num;
+         pVosHeadPkt = pVosCurPkt;
+      } else {
+         VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+                   "%s: Non-AMSDU Drop the replay packet PN: [0x%llX]",
+                   __func__, pVosCurPkt->pn_num);
+         pClientSTA->ulTotalReplayPacketsDetected++;
+
+         pfreeVosPkt = pVosCurPkt;
+         pfreeVosPkt->pNext = NULL;
+         vos_pkt_return_packet(pfreeVosPkt);
+
+         if (pVosHeadPkt != NULL) {
+            pVosHeadPkt->pNext = pNextVosPkt;
+         }
+         else {
+            *vosDataBuff = pNextVosPkt;
+         }
+      }
+
+      pVosCurPkt = pNextVosPkt;
+   } while (pVosCurPkt);
+}
diff --git a/CORE/TL/src/wlan_qct_tli_ba.h b/CORE/TL/src/wlan_qct_tli_ba.h
index 6265e89..e1d68e6 100644
--- a/CORE/TL/src/wlan_qct_tli_ba.h
+++ b/CORE/TL/src/wlan_qct_tli_ba.h
@@ -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.
  *
@@ -394,4 +394,14 @@
    v_U8_t                 ucSlotIndex
 );
 
+/**
+ * WLANTL_ReorderReplayCheck - Do reorder PN replay check
+ * @pClientSTA: pointer to sta context
+ * @vosDataBuff: pointer to address of data buffer
+ * @ucTid: Tid value
+ *
+ * Return: None
+ */
+void WLANTL_ReorderReplayCheck(WLANTL_STAClientType *pClientSTA,
+                               vos_pkt_t **vosDataBuff, v_U8_t ucTid);
 #endif /* #ifndef WLAN_QCT_TLI_H */
diff --git a/CORE/VOSS/inc/i_vos_packet.h b/CORE/VOSS/inc/i_vos_packet.h
index f0bc8ab..173d792 100644
--- a/CORE/VOSS/inc/i_vos_packet.h
+++ b/CORE/VOSS/inc/i_vos_packet.h
@@ -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.
  *
@@ -127,6 +127,8 @@
    // user data pointers
    v_VOID_t *pvUserData[ VOS_PKT_USER_DATA_ID_MAX ];
 
+   v_U64_t pn_num;
+
    // magic number for verifying this is really a struct vos_pkt_t
    v_U32_t magic;
 };
diff --git a/CORE/VOSS/inc/vos_packet.h b/CORE/VOSS/inc/vos_packet.h
index ad838d7..ab949c8 100644
--- a/CORE/VOSS/inc/vos_packet.h
+++ b/CORE/VOSS/inc/vos_packet.h
@@ -565,6 +565,14 @@
                                       v_BOOL_t unchainPacket );
 
 
+/**
+ * vos_is_pkt_chain() - Check for chain of packets
+ * @pPacket: pointer to chain of packet list
+ *
+ * Return: true if chain of packets or false otherwise
+ */
+bool vos_is_pkt_chain(vos_pkt_t *pPacket);
+
 /**--------------------------------------------------------------------------
   
   \brief vos_pkt_get_data_vector() - Get data vectors from a voss Packet
diff --git a/CORE/VOSS/src/vos_packet.c b/CORE/VOSS/src/vos_packet.c
index 0135682..1765c80 100644
--- a/CORE/VOSS/src/vos_packet.c
+++ b/CORE/VOSS/src/vos_packet.c
@@ -1597,6 +1597,15 @@
    }
 }
 
+
+bool vos_is_pkt_chain(vos_pkt_t *pPacket)
+{
+   if (pPacket->pNext != NULL)
+      return true;
+   else
+      return false;
+}
+
 /**--------------------------------------------------------------------------
 
   \brief vos_pkt_get_data_vector() - Get data vectors from a voss Packet