/* DTS Rx packet function. 
 * This function should be invoked by the transport device to indicate 
 * reception of a frame.
 * Parameters:
 * pContext:Cookie that should be passed back to the caller 
 * pFrame:Refernce to PAL frame.
 * Return Value: SUCCESS  Completed successfully.
 *     FAILURE_XXX  Request was rejected due XXX Reason.
 *
 */
wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType channel)
{
  WDI_DS_ClientDataType *pClientData = 
    (WDI_DS_ClientDataType*)(pContext);
  wpt_boolean       bASF, bFSF, bLSF, bAEF;
  wpt_uint8                   ucMPDUHOffset, ucMPDUHLen, ucTid;
  wpt_uint8                   *pBDHeader;
  wpt_uint16                  usMPDUDOffset, usMPDULen;
  WDI_DS_RxMetaInfoType     *pRxMetadata;
  wpt_uint8                  isFcBd = 0;

  tpSirMacFrameCtl  pMacFrameCtl;
  // Do Sanity checks
  if(NULL == pContext || NULL == pFrame){
    return eWLAN_PAL_STATUS_E_FAILURE;
  }

  /*------------------------------------------------------------------------
    Extract BD header and check if valid
    ------------------------------------------------------------------------*/
  pBDHeader = (wpt_uint8*)wpalPacketGetRawBuf(pFrame);
  if(NULL == pBDHeader)
  {
    DTI_TRACE( DTI_TRACE_LEVEL_ERROR,
       "WLAN TL:BD header received NULL - dropping packet");
    wpalPacketFree(pFrame);
    return eWLAN_PAL_STATUS_E_FAILURE;
  }
  WDI_SwapRxBd(pBDHeader);

  ucMPDUHOffset = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_OFFSET(pBDHeader);
  usMPDUDOffset = (wpt_uint16)WDI_RX_BD_GET_MPDU_D_OFFSET(pBDHeader);
  usMPDULen     = (wpt_uint16)WDI_RX_BD_GET_MPDU_LEN(pBDHeader);
  ucMPDUHLen    = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_LEN(pBDHeader);
  ucTid         = (wpt_uint8)WDI_RX_BD_GET_TID(pBDHeader);

  /* If RX thread drain small size of frame from HW too fast
   * Sometimes HW cannot handle interrupt fast enough
   * And system crash might happen
   * To avoid system crash, input 1usec delay each frame draining
   * within host side, if frame size is smaller that threshold.
   * This is SW work around, to fix HW problem
   * Throughput and SnS test done successfully */
  if (usMPDULen < DTS_RX_DELAY_FRAMESIZE_THRESHOLD)
  {
    wpalBusyWait(1);
  }

  /*------------------------------------------------------------------------
    Gather AMSDU information 
    ------------------------------------------------------------------------*/
  bASF = WDI_RX_BD_GET_ASF(pBDHeader);
  bAEF = WDI_RX_BD_GET_AEF(pBDHeader);
  bFSF = WDI_RX_BD_GET_ESF(pBDHeader);
  bLSF = WDI_RX_BD_GET_LSF(pBDHeader);
  isFcBd = WDI_RX_FC_BD_GET_FC(pBDHeader);

  DTI_TRACE( DTI_TRACE_LEVEL_INFO,
      "WLAN TL:BD header processing data: HO %d DO %d Len %d HLen %d"
      " Tid %d BD %d",
      ucMPDUHOffset, usMPDUDOffset, usMPDULen, ucMPDUHLen, ucTid,
      WDI_RX_BD_HEADER_SIZE);

  if(!isFcBd)
  {
      if(usMPDUDOffset <= ucMPDUHOffset || usMPDULen < ucMPDUHLen) {
        DTI_TRACE( DTI_TRACE_LEVEL_ERROR,
            "WLAN TL:BD header corrupted - dropping packet");
        /* Drop packet ???? */ 
        wpalPacketFree(pFrame);
        return eWLAN_PAL_STATUS_SUCCESS;
      }

      if((ucMPDUHOffset < WDI_RX_BD_HEADER_SIZE) &&  (!(bASF && !bFSF))){
        /* AMSDU case, ucMPDUHOffset = 0  it should be hancdled seperatly */
        /* Drop packet ???? */ 
        wpalPacketFree(pFrame);
        return eWLAN_PAL_STATUS_SUCCESS;
      }

      /* AMSDU frame, but not first sub-frame
       * No MPDU header, MPDU header offset is 0
       * Total frame size is actual frame size + MPDU data offset */
      if((ucMPDUHOffset < WDI_RX_BD_HEADER_SIZE) && (bASF && !bFSF)){
        ucMPDUHOffset = usMPDUDOffset;
      }

      if(VPKT_SIZE_BUFFER < (usMPDULen+ucMPDUHOffset)){
        DTI_TRACE( DTI_TRACE_LEVEL_FATAL,
                   "Invalid Frame size, might memory corrupted");

        /* Size of the packet tranferred by the DMA engine is
         * greater than the the memory allocated for the skb
         */
        WPAL_BUG(0);

        wpalPacketFree(pFrame);
        return eWLAN_PAL_STATUS_SUCCESS;
      }
      if(eWLAN_PAL_STATUS_SUCCESS != wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset))
      {
          DTI_TRACE( DTI_TRACE_LEVEL_ERROR, "Invalid Frame Length, Frame dropped..");
          wpalPacketFree(pFrame);
          return eWLAN_PAL_STATUS_SUCCESS;
      }
      if(eWLAN_PAL_STATUS_SUCCESS != wpalPacketRawTrimHead(pFrame, ucMPDUHOffset))
      {
          DTI_TRACE( DTI_TRACE_LEVEL_ERROR, "Failed to trim Raw Packet Head, Frame dropped..");
          wpalPacketFree(pFrame);
          return eWLAN_PAL_STATUS_SUCCESS;
      }
     

      pRxMetadata = WDI_DS_ExtractRxMetaData(pFrame);

      pRxMetadata->fc = isFcBd;
      pRxMetadata->staId = WDI_RX_BD_GET_STA_ID(pBDHeader);
      pRxMetadata->addr3Idx = WDI_RX_BD_GET_ADDR3_IDX(pBDHeader);
      pRxMetadata->rxChannel = WDI_RX_BD_GET_RX_CHANNEL(pBDHeader);
      pRxMetadata->rfBand = WDI_RX_BD_GET_RFBAND(pBDHeader);
      pRxMetadata->rtsf = WDI_RX_BD_GET_RTSF(pBDHeader);
      pRxMetadata->bsf = WDI_RX_BD_GET_BSF(pBDHeader);
      pRxMetadata->scan = WDI_RX_BD_GET_SCAN(pBDHeader);
      pRxMetadata->dpuSig = WDI_RX_BD_GET_DPU_SIG(pBDHeader);
      pRxMetadata->ft = WDI_RX_BD_GET_FT(pBDHeader);
      pRxMetadata->ne = WDI_RX_BD_GET_NE(pBDHeader);
      pRxMetadata->llcr = WDI_RX_BD_GET_LLCR(pBDHeader);
      pRxMetadata->bcast = WDI_RX_BD_GET_UB(pBDHeader);
      pRxMetadata->tid = ucTid;
      pRxMetadata->dpuFeedback = WDI_RX_BD_GET_DPU_FEEDBACK(pBDHeader);
      pRxMetadata->rateIndex = WDI_RX_BD_GET_RATEINDEX(pBDHeader);
      pRxMetadata->rxpFlags = WDI_RX_BD_GET_RXPFLAGS(pBDHeader);
      pRxMetadata->mclkRxTimestamp = WDI_RX_BD_GET_TIMESTAMP(pBDHeader);
#ifdef WLAN_FEATURE_11W
      pRxMetadata->rmf = WDI_RX_BD_GET_RMF(pBDHeader);
#endif
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
      pRxMetadata->offloadScanLearn = WDI_RX_BD_GET_OFFLOADSCANLEARN(pBDHeader);
      pRxMetadata->roamCandidateInd = WDI_RX_BD_GET_ROAMCANDIDATEIND(pBDHeader);
#endif

      /* typeSubtype in BD doesn't look like correct. Fill from frame ctrl
         TL does it for Volans but TL does not know BD for Prima. WDI should do it */
      if ( 0 == WDI_RX_BD_GET_FT(pBDHeader) ) {
        if ( bASF ) {
          pRxMetadata->subtype = WDI_MAC_DATA_QOS_DATA;
          pRxMetadata->type    = WDI_MAC_DATA_FRAME;
        } else {
          pMacFrameCtl = (tpSirMacFrameCtl)(((wpt_uint8*)pBDHeader) + ucMPDUHOffset);
          pRxMetadata->subtype = pMacFrameCtl->subType;
          pRxMetadata->type    = pMacFrameCtl->type;
        }
      } else {
        pMacFrameCtl = (tpSirMacFrameCtl)(((wpt_uint8*)pBDHeader) + WDI_RX_BD_HEADER_SIZE);
        pRxMetadata->subtype = pMacFrameCtl->subType;
        pRxMetadata->type    = pMacFrameCtl->type;
      }

      pRxMetadata->mpduHeaderPtr = pBDHeader + ucMPDUHOffset;
      pRxMetadata->mpduDataPtr = pBDHeader + usMPDUDOffset;
      pRxMetadata->mpduLength = usMPDULen;
      pRxMetadata->mpduHeaderLength = ucMPDUHLen;

      /*------------------------------------------------------------------------
        Gather AMPDU information 
        ------------------------------------------------------------------------*/
      pRxMetadata->ampdu_reorderOpcode  = (wpt_uint8)WDI_RX_BD_GET_BA_OPCODE(pBDHeader);
      pRxMetadata->ampdu_reorderSlotIdx = (wpt_uint8)WDI_RX_BD_GET_BA_SI(pBDHeader);
      pRxMetadata->ampdu_reorderFwdIdx  = (wpt_uint8)WDI_RX_BD_GET_BA_FI(pBDHeader);
      pRxMetadata->currentPktSeqNo       = (wpt_uint16)WDI_RX_BD_GET_BA_CSN(pBDHeader);


      /*------------------------------------------------------------------------
        Gather AMSDU information 
        ------------------------------------------------------------------------*/
      pRxMetadata->amsdu_asf  =  bASF;
      pRxMetadata->amsdu_aef  =  bAEF;
      pRxMetadata->amsdu_esf  =  bFSF;
      pRxMetadata->amsdu_lsf  =  bLSF;
      pRxMetadata->amsdu_size =  WDI_RX_BD_GET_AMSDU_SIZE(pBDHeader);

      pRxMetadata->rssi0 = WDI_RX_BD_GET_RSSI0(pBDHeader);
      pRxMetadata->rssi1 = WDI_RX_BD_GET_RSSI1(pBDHeader);


        /* Missing: 
      wpt_uint32 fcSTATxQStatus:8;
      wpt_uint32 fcSTAThreshIndMask:8;
      wpt_uint32 fcSTAPwrSaveStateMask:8;
      wpt_uint32 fcSTAValidMask:8;

      wpt_uint8 fcSTATxQLen[8]; // one byte per STA. 
      wpt_uint8 fcSTACurTxRate[8]; // current Tx rate for each sta.   
      unknownUcastPkt 
      */

      pRxMetadata->replayCount = WDTS_GetReplayCounterFromRxBD(pBDHeader);
      pRxMetadata->snr = WDI_RX_BD_GET_SNR(pBDHeader); 

      /* 
       * PAL BD pointer information needs to be populated 
       */ 
      WPAL_PACKET_SET_BD_POINTER(pFrame, pBDHeader);
      WPAL_PACKET_SET_BD_LENGTH(pFrame, sizeof(WDI_RxBdType));

      // Invoke Rx complete callback
      pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame);  
  }
  else
  {
      wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset);
      wpalPacketRawTrimHead(pFrame, ucMPDUHOffset);

      pRxMetadata = WDI_DS_ExtractRxMetaData(pFrame);
      //flow control related
      pRxMetadata->fc = isFcBd;
      pRxMetadata->mclkRxTimestamp = WDI_RX_BD_GET_TIMESTAMP(pBDHeader);
      pRxMetadata->fcStaTxDisabledBitmap = WDI_RX_FC_BD_GET_STA_TX_DISABLED_BITMAP(pBDHeader);
      pRxMetadata->fcSTAValidMask = WDI_RX_FC_BD_GET_STA_VALID_MASK(pBDHeader);
      // Invoke Rx complete callback
      pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame);  
  }

  //Log the RX Stats
  if(gDsTrafficStats.running && pRxMetadata->staId < HAL_NUM_STA)
  {
     if(pRxMetadata->rateIndex < WDTS_MAX_RATE_NUM)
     {
        if(pRxMetadata->type == WDI_MAC_DATA_FRAME)
        {
           gDsTrafficStats.rxStats[pRxMetadata->staId][pRxMetadata->rateIndex].rxBytesRcvd +=
              pRxMetadata->mpduLength;
           gDsTrafficStats.rxStats[pRxMetadata->staId][pRxMetadata->rateIndex].rxPacketsRcvd++;
        }
     }
  }
  return eWLAN_PAL_STATUS_SUCCESS;
}
/* DTS Rx packet function. 
 * This function should be invoked by the transport device to indicate 
 * reception of a frame.
 * Parameters:
 * pContext:Cookie that should be passed back to the caller 
 * pFrame:Refernce to PAL frame.
 * Return Value: SUCCESS  Completed successfully.
 *     FAILURE_XXX  Request was rejected due XXX Reason.
 *
 */
wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType channel)
{
  WDI_DS_ClientDataType *pClientData = 
    (WDI_DS_ClientDataType*)(pContext);
  wpt_boolean       bASF, bFSF, bLSF, bAEF;
  wpt_uint8                   ucMPDUHOffset, ucMPDUHLen, ucTid;
  wpt_uint8                   *pBDHeader;
  wpt_uint16                  usMPDUDOffset, usMPDULen;
  WDI_DS_RxMetaInfoType     *pRxMetadata;
  wpt_uint8                  isFcBd = 0;

  tpSirMacFrameCtl  pMacFrameCtl;
  // Do Sanity checks
  if(NULL == pContext || NULL == pFrame){
    return eWLAN_PAL_STATUS_E_FAILURE;
  }

  /*------------------------------------------------------------------------
    Extract BD header and check if valid
    ------------------------------------------------------------------------*/
  pBDHeader = (wpt_uint8*)wpalPacketGetRawBuf(pFrame);
  if(NULL == pBDHeader)
  {
    DTI_TRACE( DTI_TRACE_LEVEL_ERROR,
       "WLAN TL:BD header received NULL - dropping packet");
    wpalPacketFree(pFrame);
    return eWLAN_PAL_STATUS_E_FAILURE;
  }
  WDI_SwapRxBd(pBDHeader);

  ucMPDUHOffset = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_OFFSET(pBDHeader);
  usMPDUDOffset = (wpt_uint16)WDI_RX_BD_GET_MPDU_D_OFFSET(pBDHeader);
  usMPDULen     = (wpt_uint16)WDI_RX_BD_GET_MPDU_LEN(pBDHeader);
  ucMPDUHLen    = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_LEN(pBDHeader);
  ucTid         = (wpt_uint8)WDI_RX_BD_GET_TID(pBDHeader);

  /*------------------------------------------------------------------------
    Gather AMSDU information 
    ------------------------------------------------------------------------*/
  bASF = WDI_RX_BD_GET_ASF(pBDHeader);
  bAEF = WDI_RX_BD_GET_AEF(pBDHeader);
  bFSF = WDI_RX_BD_GET_ESF(pBDHeader);
  bLSF = WDI_RX_BD_GET_LSF(pBDHeader);
  isFcBd = WDI_RX_FC_BD_GET_FC(pBDHeader);

  DTI_TRACE( DTI_TRACE_LEVEL_INFO,
      "WLAN TL:BD header processing data: HO %d DO %d Len %d HLen %d"
      " Tid %d BD %d",
      ucMPDUHOffset, usMPDUDOffset, usMPDULen, ucMPDUHLen, ucTid,
      WDI_RX_BD_HEADER_SIZE);

  if(!isFcBd)
  {
      if(usMPDUDOffset <= ucMPDUHOffset || usMPDULen < ucMPDUHLen) {
        DTI_TRACE( DTI_TRACE_LEVEL_ERROR,
            "WLAN TL:BD header corrupted - dropping packet");
        /* Drop packet ???? */ 
        wpalPacketFree(pFrame);
        return eWLAN_PAL_STATUS_SUCCESS;
      }

      if((ucMPDUHOffset < WDI_RX_BD_HEADER_SIZE) &&  (!(bASF && !bFSF))){
        /* AMSDU case, ucMPDUHOffset = 0  it should be hancdled seperatly */
        /* Drop packet ???? */ 
        wpalPacketFree(pFrame);
        return eWLAN_PAL_STATUS_SUCCESS;
      }

      /* AMSDU frame, but not first sub-frame
       * No MPDU header, MPDU header offset is 0
       * Total frame size is actual frame size + MPDU data offset */
      if((ucMPDUHOffset < WDI_RX_BD_HEADER_SIZE) && (bASF && !bFSF)){
        ucMPDUHOffset = usMPDUDOffset;
      }

      if(VPKT_SIZE_BUFFER < (usMPDULen+ucMPDUHOffset)){
        DTI_TRACE( DTI_TRACE_LEVEL_FATAL,
                   "Invalid Frame size, might memory corrupted");
        wpalPacketFree(pFrame);
        return eWLAN_PAL_STATUS_SUCCESS;
      }
      wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset);
      wpalPacketRawTrimHead(pFrame, ucMPDUHOffset);

     

      pRxMetadata = WDI_DS_ExtractRxMetaData(pFrame);

      pRxMetadata->fc = isFcBd;
      pRxMetadata->staId = WDI_RX_BD_GET_STA_ID(pBDHeader);
      pRxMetadata->addr3Idx = WDI_RX_BD_GET_ADDR3_IDX(pBDHeader);
      pRxMetadata->rxChannel = WDI_RX_BD_GET_RX_CHANNEL(pBDHeader);
      pRxMetadata->rtsf = WDI_RX_BD_GET_RTSF(pBDHeader);
      pRxMetadata->bsf = WDI_RX_BD_GET_BSF(pBDHeader);
      pRxMetadata->scan = WDI_RX_BD_GET_SCAN(pBDHeader);
      pRxMetadata->dpuSig = WDI_RX_BD_GET_DPU_SIG(pBDHeader);
      pRxMetadata->ft = WDI_RX_BD_GET_FT(pBDHeader);
      pRxMetadata->ne = WDI_RX_BD_GET_NE(pBDHeader);
      pRxMetadata->llcr = WDI_RX_BD_GET_LLCR(pBDHeader);
      pRxMetadata->bcast = WDI_RX_BD_GET_UB(pBDHeader);
      pRxMetadata->tid = ucTid;
      pRxMetadata->dpuFeedback = WDI_RX_BD_GET_DPU_FEEDBACK(pBDHeader);
      pRxMetadata->rateIndex = WDI_RX_BD_GET_RATEINDEX(pBDHeader);
      pRxMetadata->rxpFlags = WDI_RX_BD_GET_RXPFLAGS(pBDHeader);
      pRxMetadata->mclkRxTimestamp = WDI_RX_BD_GET_TIMESTAMP(pBDHeader);

      /* typeSubtype in BD doesn't look like correct. Fill from frame ctrl
         TL does it for Volans but TL does not know BD for Prima. WDI should do it */
      if ( 0 == WDI_RX_BD_GET_FT(pBDHeader) ) {
        if ( bASF ) {
          pRxMetadata->subtype = WDI_MAC_DATA_QOS_DATA;
          pRxMetadata->type    = WDI_MAC_DATA_FRAME;
        } else {
          pMacFrameCtl = (tpSirMacFrameCtl)(((wpt_uint8*)pBDHeader) + ucMPDUHOffset);
          pRxMetadata->subtype = pMacFrameCtl->subType;
          pRxMetadata->type    = pMacFrameCtl->type;
        }
      } else {
        pMacFrameCtl = (tpSirMacFrameCtl)(((wpt_uint8*)pBDHeader) + WDI_RX_BD_HEADER_SIZE);
        pRxMetadata->subtype = pMacFrameCtl->subType;
        pRxMetadata->type    = pMacFrameCtl->type;
      }

      pRxMetadata->mpduHeaderPtr = pBDHeader + ucMPDUHOffset;
      pRxMetadata->mpduDataPtr = pBDHeader + usMPDUDOffset;
      pRxMetadata->mpduLength = usMPDULen;
      pRxMetadata->mpduHeaderLength = ucMPDUHLen;

      /*------------------------------------------------------------------------
        Gather AMPDU information 
        ------------------------------------------------------------------------*/
      pRxMetadata->ampdu_reorderOpcode  = (wpt_uint8)WDI_RX_BD_GET_BA_OPCODE(pBDHeader);
      pRxMetadata->ampdu_reorderSlotIdx = (wpt_uint8)WDI_RX_BD_GET_BA_SI(pBDHeader);
      pRxMetadata->ampdu_reorderFwdIdx  = (wpt_uint8)WDI_RX_BD_GET_BA_FI(pBDHeader);
      pRxMetadata->currentPktSeqNo       = (wpt_uint8)WDI_RX_BD_GET_BA_CSN(pBDHeader);


      /*------------------------------------------------------------------------
        Gather AMSDU information 
        ------------------------------------------------------------------------*/
      pRxMetadata->amsdu_asf  =  bASF;
      pRxMetadata->amsdu_aef  =  bAEF;
      pRxMetadata->amsdu_esf  =  bFSF;
      pRxMetadata->amsdu_lsf  =  bLSF;
      pRxMetadata->amsdu_size =  WDI_RX_BD_GET_AMSDU_SIZE(pBDHeader);

      pRxMetadata->rssi0 = WDI_RX_BD_GET_RSSI0(pBDHeader);
      pRxMetadata->rssi1 = WDI_RX_BD_GET_RSSI1(pBDHeader);


        /* Missing: 
      wpt_uint32 fcSTATxQStatus:8;
      wpt_uint32 fcSTAThreshIndMask:8;
      wpt_uint32 fcSTAPwrSaveStateMask:8;
      wpt_uint32 fcSTAValidMask:8;

      wpt_uint8 fcSTATxQLen[8]; // one byte per STA. 
      wpt_uint8 fcSTACurTxRate[8]; // current Tx rate for each sta.   
      unknownUcastPkt 
      */

      pRxMetadata->replayCount = WDTS_GetReplayCounterFromRxBD(pBDHeader);
      pRxMetadata->snr = WDI_RX_BD_GET_SNR(pBDHeader); 

      /* 
       * PAL BD pointer information needs to be populated 
       */ 
      WPAL_PACKET_SET_BD_POINTER(pFrame, pBDHeader);
      WPAL_PACKET_SET_BD_LENGTH(pFrame, sizeof(WDI_RxBdType));

      // Invoke Rx complete callback
      pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame);  
  }
  else
  {
      wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset);
      wpalPacketRawTrimHead(pFrame, ucMPDUHOffset);

      pRxMetadata = WDI_DS_ExtractRxMetaData(pFrame);
      //flow control related
      pRxMetadata->fc = isFcBd;
      pRxMetadata->fcStaTxDisabledBitmap = WDI_RX_FC_BD_GET_STA_TX_DISABLED_BITMAP(pBDHeader);
      pRxMetadata->fcSTAValidMask = WDI_RX_FC_BD_GET_STA_VALID_MASK(pBDHeader);
      // Invoke Rx complete callback
      pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame);  
  }
  return eWLAN_PAL_STATUS_SUCCESS;

}