Initial commit
[o-du/l2.git] / src / 5gnrrlc / kw_utl_ul.c
diff --git a/src/5gnrrlc/kw_utl_ul.c b/src/5gnrrlc/kw_utl_ul.c
new file mode 100755 (executable)
index 0000000..ff12ea8
--- /dev/null
@@ -0,0 +1,1222 @@
+/*******************************************************************************
+################################################################################
+#   Copyright (c) [2017-2019] [Radisys]                                        #
+#                                                                              #
+#   Licensed under the Apache License, Version 2.0 (the "License");            #
+#   you may not use this file except in compliance with the License.           #
+#   You may obtain a copy of the License at                                    #
+#                                                                              #
+#       http://www.apache.org/licenses/LICENSE-2.0                             #
+#                                                                              #
+#   Unless required by applicable law or agreed to in writing, software        #
+#   distributed under the License is distributed on an "AS IS" BASIS,          #
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
+#   See the License for the specific language governing permissions and        #
+#   limitations under the License.                                             #
+################################################################################
+*******************************************************************************/
+
+/**********************************************************************
+
+     Name:     LTE-RLC Layer 
+  
+     Type:     C file
+  
+     Desc:     Source code for RLC Utility Module
+               This file contains following functions
+
+                  --kwUtlSndToLi
+                  --kwUtlRcvFrmLi
+                  --kwUtlEmptySduQ
+                  --kwUtlSndDatInd 
+                  --kwUtlShutDown
+
+     File:     kw_utl_ul.c
+
+**********************************************************************/
+static const char* RLOG_MODULE_NAME="UTL";
+static int RLOG_MODULE_ID=2048;
+static int RLOG_FILE_ID=210;
+
+/** @file kw_utl_ul.c
+@brief RLC Utility Module 
+*/
+
+/* header (.h) include files */
+#include "envopt.h"        /* environment options */
+#include "envdep.h"        /* environment dependent */
+#include "envind.h"        /* environment independent */
+/* kw005.201 added support for L2 Measurement */
+#ifdef LTE_L2_MEAS
+#include <sys/time.h>
+#endif
+
+#include "gen.h"           /* general */
+#include "ssi.h"           /* system services */
+#include "cm5.h"           /* common timer defines */
+#include "cm_tkns.h"       /* common tokens defines */
+#include "cm_mblk.h"       /* common memory allocation library defines */
+#include "cm_llist.h"      /* common link list  defines  */
+#include "cm_hash.h"       /* common hash list  defines */
+#include "cm_lte.h"        /* common LTE defines */
+#include "ckw.h"           /* CKW defines */
+#include "kwu.h"           /* KWU defines */
+#include "lkw.h"           /* LKW defines */
+#include "rgu.h"           /* RGU defines */
+
+#include "kw_env.h"        /* RLC environment options */
+#include "kw.h"            /* RLC defines */
+#include "kw_err.h"        /* Error defines */
+#include "kw_ul.h"         /* RLC Uplink defines */
+
+/* extern (.x) include files */
+#include "gen.x"           /* general */
+#include "ssi.x"           /* system services */
+
+#include "cm5.x"           /* common timer library */
+#include "cm_tkns.x"       /* common tokens */
+#include "cm_mblk.x"       /* common memory allocation */
+#include "cm_llist.x"      /* common link list */
+#include "cm_hash.x"       /* common hash list */
+#include "cm_lte.x"        /* common LTE includes */
+#include "cm_lib.x"        /* common memory allocation library */
+#include "ckw.x"           /* CKW includes */
+#include "kwu.x"           /* KWU includes */
+#include "lkw.x"           /* LKW includes */
+#include "rgu.x"           /* RGU includes */
+
+#include "kw.x"            /* RLC inlcudes */
+#include "kw_ul.x"         /* RLC uplink includes */
+#include "ss_rbuf.h"
+#include "ss_rbuf.x"
+#ifdef SS_RBUF
+PUBLIC S16 SMrkUlPkt(Buffer *mbuf);
+#endif
+PUBLIC KwAmRecBuf* kwUtlGetRecBuf(CmLListCp *recBufLst, KwSn sn);
+#define KW_MODULE (KW_DBGMASK_DUT | KW_DBGMASK_UL) /* for debugging purpose */
+
+
+/**
+ *
+ * @brief 
+ *        Handler for receiving data for multiple logical channels from MAC.
+ *
+ * @details
+ *        This function receives the data sent by MAC for one or more 
+ *        logical channels.It calls the UMM or AMM functions to process
+ *        the PDUs and send them to the uppper layer.  
+ *
+ * @param[in] gCb          - RLC instance control block 
+ * @param[in] datIndInfo   - Data Indication Information containing the PDU(s)
+ *                            for one or more logical channels  
+ *
+ * @return  S16
+ *      -# ROK 
+ *      -# RFAILED
+ *
+ */
+#ifdef ANSI
+PUBLIC S16 kwUtlRcvFrmLi
+(
+KwCb           *gCb,                              
+KwDatIndInfo   *datIndInfo                       
+)
+#else
+PUBLIC S16 kwUtlRcvFrmLi(gCb,datIndInfo)  
+KwCb           *gCb;                     
+KwDatIndInfo   *datIndInfo;             
+#endif
+{
+   U32         count;      /* Loop Counter */
+   KwPduInfo   *pduInfo;   /* PDU Information */
+   KwUlRbCb    *rbCb;      /* RB Control Block */
+   KwUlUeCb    *ueCb;      /* UE Control Block */
+/* kw005.201 added support for L2 Measurement */
+
+   TRC2(kwUtlRcvFrmLi)
+
+
+   ueCb = NULLP;
+   
+   /* fetch UeCb  */
+   if( ROK != kwDbmFetchUlUeCb(gCb,datIndInfo->rnti,datIndInfo->cellId,&(ueCb)))
+   {
+      /* Fetch UeCb failed */
+      RLOG_ARG1(L_ERROR,DBG_CELLID,datIndInfo->cellId,
+               "UEID:%d UeCb not found",
+               datIndInfo->rnti);
+      /* free the buffers inside the datIndInfo */
+      U32 i,j;
+      for(i = 0; i< datIndInfo->numLch; i++)
+      {
+         for(j = 0; j < datIndInfo->lchData[i].pdu.numPdu; j++)
+         {
+            if(datIndInfo->lchData[i].pdu.mBuf[j])
+            {
+               KW_FREE_BUF_WC(datIndInfo->lchData[i].pdu.mBuf[j]);
+            }
+         }
+      }
+      
+      RETVALUE(RFAILED);
+   }
+
+#ifdef LTE_L2_MEAS
+
+   if (RGU_L2M_UL_BURST_START == datIndInfo->burstInd)
+   {
+      ueCb->isUlBurstActive = TRUE;
+   }
+   else
+   {
+      ueCb->firstPacketTTI = 0;
+      ueCb->isUlBurstActive = FALSE;
+   }
+#endif
+   for ( count = 0;count < datIndInfo->numLch; count++ )
+   {
+      rbCb = ueCb->lCh[datIndInfo->lchData[count].lcId - 1].ulRbCb;
+      /* kw002.201 Removed allocation of pduInfo */ 
+      pduInfo = &(datIndInfo->lchData[count].pdu);
+      /* Fix for CR ccpu00138374,sometimes rbCb is NULL in UL path,
+       * So inorder to avoid the crash, added this preventive check
+       */
+      if(rbCb == NULLP)
+      {
+         U32 j;
+         for(j = 0; j < pduInfo->numPdu; j++)
+         {
+            if(pduInfo->mBuf[j])
+            {
+               KW_FREE_BUF_WC(pduInfo->mBuf[j]);
+            }
+         }
+         continue;
+      }
+
+#ifdef SS_RBUF
+      SMrkUlPkt(pduInfo->mBuf[0]);
+#endif
+      if ( rbCb->mode == CM_LTE_MODE_UM )
+      {
+/* kw005.201 added support for L2 Measurement */
+#ifdef LTE_L2_MEAS
+         kwUmmProcessPdus(gCb,rbCb, pduInfo, datIndInfo->ttiCnt);
+#else
+         kwUmmProcessPdus(gCb,rbCb,pduInfo);
+#endif
+      }
+      else if (rbCb->mode == CM_LTE_MODE_AM )
+      {
+/* kw005.201 added support for L2 Measurement */
+#ifdef LTE_L2_MEAS
+         kwAmmProcessPdus(gCb,rbCb,  pduInfo, datIndInfo->ttiCnt);
+#else
+         kwAmmProcessPdus(gCb,rbCb,pduInfo);
+#endif
+      }
+   }
+   RETVALUE(ROK);
+}
+
+/**
+ *
+ * @brief 
+ *    Handler for sending Data Indication to the upper layer. 
+ * 
+ * @Details
+ *    This function is used to send re-assembled SDU to the upper layer.
+ *
+ * @param[in]  gCb    - RLC instance Control Block 
+ * @param[in]  rbCb   - RB Control Block 
+ * @param[in]  sdu    - SDU to be sent to upper layer 
+ *
+ * @return  S16
+ *      -# ROK 
+ */
+#ifdef ANSI
+PUBLIC S16 kwUtlSndDatInd
+(
+KwCb       *gCb,
+KwUlRbCb   *rbCb,                   
+Buffer     *sdu                    
+)
+#else
+PUBLIC S16 kwUtlSndDatInd(gCb,rbCb,sdu)
+KwCb       *gCb;
+KwUlRbCb   *rbCb;                  
+Buffer     *sdu;                    
+#endif
+{
+#ifndef KW_PDCP
+   KwKwuSapCb      *kwKwSap;     /* KWU SAP Information */
+   KwuDatIndInfo   *datIndInfo;   /* Data Indication Information */
+   KwuDatIndInfo datIndInfoTmp;
+#endif
+
+   TRC3(kwUtlSndDatInd)
+
+
+#ifndef KW_PDCP
+   kwKwSap = gCb->u.ulCb->kwuUlSap + KW_UI_PDCP;
+   /* Creating static memory for KwuDatIndInfo. #else will be 
+    * removed once the testing is done on all platforms */
+   datIndInfo = &datIndInfoTmp;
+
+#if (ERRCLASS & ERRCLS_ADD_RES )
+   if ( datIndInfo == NULLP  )
+   {
+      RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
+               "Memory allocation failed UEID:%d CELLID:%d",
+               rbCb->rlcId.ueId,
+               rbCb->rlcId.cellId);
+      KW_FREE_BUF(sdu);
+      RETVALUE(RFAILED);
+   }
+#endif /* ERRCLASS & ERRCLS_ADD_RES */
+
+   KW_MEM_CPY(&(datIndInfo->rlcId),&(rbCb->rlcId),sizeof(CmLteRlcId));
+   /* Set the "isOutofSeq" flag for each packet 
+    * If packets are in-sequence set flag as TRUE else FALSE */
+   datIndInfo->isOutOfSeq = rbCb->m.amUl.isOutOfSeq; 
+#endif /* KW_PDCP */
+   
+   /* If trace flag is enabled send the trace indication */
+   if(gCb->init.trc == TRUE)
+   {
+      /* Populate the trace params */
+      kwLmmSendTrc(gCb,KWU_EVT_DAT_IND, sdu);
+   }
+#ifndef KW_PDCP
+
+   KwUiKwuDatInd(&kwKwSap->pst, kwKwSap->suId, datIndInfo, sdu);
+#endif   
+   RETVALUE(ROK);
+} /* kwUtlSndDatInd */
+
+
+PRIVATE Void dumpRLCUlRbInformation(KwUlRbCb* ulRbCb)
+{
+   if(ulRbCb->mode == CM_LTE_MODE_UM)
+   {
+      U32 i;
+      U32 pdusInReceptionBuffer = 0;
+      U32 windSz  = ulRbCb->m.umUl.umWinSz << 1;
+
+      for(i = 0; i< windSz; i++)
+      {
+         if(ulRbCb->m.umUl.recBuf[i] != NULLP)
+         {
+            pdusInReceptionBuffer++;
+         }
+      }
+      
+      RLOG_ARG3(L_DEBUG,DBG_RBID,ulRbCb->rlcId.rbId,
+               "UM UL UEID:%d CELLID:%d Reception Buffer size = %d", 
+                       (int)ulRbCb->rlcId.ueId,
+                       (int)ulRbCb->rlcId.cellId,
+                       (int)pdusInReceptionBuffer);
+   }
+   else if(ulRbCb->mode == CM_LTE_MODE_AM)
+   {
+      U32 i;
+      U32 pdusInReceptionBuffer = 0;
+      U32 totalSegs = 0;
+      U32 windSz  = KW_AM_GET_WIN_SZ(ulRbCb->m.amUl.snLen) << 1;
+      
+      for(i = 0; i< windSz; i++)
+      {
+         KwAmRecBuf *recBuf = kwUtlGetRecBuf(ulRbCb->m.amUl.recBufLst, i);
+         if(recBuf != NULLP)
+         {
+            pdusInReceptionBuffer++;
+            totalSegs += (recBuf->segLst.count);
+         }
+      }
+
+      RLOG_ARG4(L_DEBUG,DBG_RBID,ulRbCb->rlcId.rbId,
+                "AM UL UEID:%d CELLID:%d Reception Buf size = %d"
+                "total segs = %d", 
+                       (int)ulRbCb->rlcId.ueId,
+                       (int)ulRbCb->rlcId.cellId,
+                       (int)pdusInReceptionBuffer, 
+                       (int)totalSegs);
+   }
+}
+
+Void DumpRLCUlDebugInformation(Void)
+{
+   KwCb* ulInst = kwCb[0]; /* TODO : Check whether UL is 0 or 1 */
+   KwUlCb* ulCb = ulInst->u.ulCb;
+   KwUlUeCb *ueCb = NULLP; 
+
+   /* Until no more ueCb is ueLstCp hash list get and delete ueCb */
+   while (ROK == cmHashListGetNext(&ulCb->ueLstCp, 
+                                   (PTR) ueCb, 
+                                   (PTR *)&ueCb))
+   {
+      U32 i;
+      for(i = 0; i< KW_MAX_SRB_PER_UE; i++)
+      {
+         KwUlRbCb* ulRbCb = ueCb->srbCb[i]; 
+         if(ulRbCb != NULLP)
+         {
+            dumpRLCUlRbInformation(ulRbCb);
+         }
+      }
+      for(i = 0; i< KW_MAX_DRB_PER_UE; i++)
+      {
+         KwUlRbCb* ulRbCb = ueCb->drbCb[i]; 
+         if(ulRbCb != NULLP)
+         {
+            dumpRLCUlRbInformation(ulRbCb);
+         }
+      }
+   }
+}
+
+
+/*
+ * kwUtlFreeUlRbCb() function is split into two functions 
+ *  -  kwAmmFreeUlRbCb() ---> gp_amm_ul.c 
+ *  -  kwUmmFreeUlRbCb() ---> gp_umm_ul.c
+ * and placed in respective files mentioned above
+ */
+
+
+
+/* kw005.201 added support for L2 Measurement */
+#ifdef LTE_L2_MEAS
+
+/**
+ *
+ * @brief 
+ *    Handler for initialisation of measurement 
+ * 
+ * @param[in]  gCb    - RLC instance Control Block 
+ *
+ * @return  S16
+ *      -# ROK 
+ */
+S16 kwUtlL2MeasUlInit(KwCb *gCb)
+{
+   U16             cntr;
+
+   gCb->u.ulCb->kwL2Cb.kwNumMeas=0;
+   for(cntr = 0; cntr < LKW_MAX_L2MEAS; cntr++)
+   {
+      cmMemset((U8 *)&(gCb->u.ulCb->kwL2Cb.kwL2EvtCb[cntr]), 0, sizeof(KwL2MeasEvtCb));
+   }
+   gCb->u.ulCb->kwL2Cb.kwL2EvtCb[KW_L2MEAS_UL_IP].measCb.measType = LKW_L2MEAS_UL_IP;
+   RETVALUE(ROK);
+}
+/**
+ *
+ * @brief
+ *
+ *        Handler to calculate the Ul Ip throughput for a LCH
+ *
+ * @b Description:
+ *
+ *
+ * @param[in] rbCb         RB control block
+ * @param[in] pdu          Pdu of LCH
+ *
+ *  @return  Void
+ *
+ */
+#ifdef ANSI
+PUBLIC  Void kwUtlCalUlIpThrPutIncTTI
+(
+KwCb                  *gCb,
+KwUlRbCb              *rbCb,
+U32                   ttiCnt
+)
+#else
+PUBLIC Void kwUtlCalUlIpThrPutIncTTI(gCb, rbCb, ttiCnt)
+KwCb                  *gCb;
+KwUlRbCb              *rbCb;
+U32                   ttiCnt;
+#endif
+{
+   VOLATILE U32     startTime = 0;
+   TRC2(kwUtlCalUlIpThrPutIncTTI)
+
+      /*starting Task*/
+      SStartTask(&startTime, PID_RLC_IP_TPT_INCTTI);
+#ifndef ALIGN_64BIT
+   RLOG_ARG4(L_UNUSED, DBG_RBID,rbCb->rlcId.rbId,"Log for ul ip throughput:"
+         "RB_MeasOn:%d ttiCnt :%ld UEID:%d CELLID:%d", 
+         rbCb->rbL2Cb.measOn,ttiCnt,
+         rbCb->rlcId.ueId,
+         rbCb->rlcId.cellId);
+#else
+   RLOG_ARG4(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, "Log for ul ip throughput:"
+         "RB_MeasOn:%d ttiCnt :%d UEID:%d CELLID:%d", 
+         rbCb->rbL2Cb.measOn,ttiCnt,
+         rbCb->rlcId.ueId,
+         rbCb->rlcId.cellId);
+#endif
+
+   /*Check if UL IP throughput measurement is ON for this RB or not*/
+   if(KW_MEAS_IS_UL_IP_MEAS_ON_FOR_RB(gCb,rbCb))              
+   {
+      if (TRUE  == rbCb->ueCb->isUlBurstActive)
+      {
+         if (ttiCnt < rbCb->l2MeasIpThruput.prevTtiCnt)
+         {
+            /*Removed Error Print*/
+         }
+         if (rbCb->l2MeasIpThruput.prevTtiCnt != 0)
+         {
+            rbCb->rbL2Cb.l2Sts[KW_L2MEAS_UL_IP]->ulIpThruput.timeSummation += 
+               (ttiCnt - rbCb->l2MeasIpThruput.prevTtiCnt);
+         }
+         else
+         {
+            rbCb->ueCb->firstPacketTTI = ttiCnt;
+         }
+         rbCb->l2MeasIpThruput.prevTtiCnt = ttiCnt;
+      }
+      else
+      {
+         rbCb->l2MeasIpThruput.prevTtiCnt = 0;
+      }
+   }   
+
+   /*stopping Task*/
+   SStopTask(startTime, PID_RLC_IP_TPT_INCTTI);
+} /* kwUtlCalUlIpThrPutIncTTI */
+
+
+/**
+ *
+ * @brief
+ *
+ *        Handler to calculate the Ul Ip throughput for a LCH
+ *
+ * @b Description:
+ *
+ *
+ * @param[in] rbCb         RB control block
+ * @param[in] pdu          Pdu of LCH
+ *
+ *  @return  Void
+ *
+ */
+#ifdef ANSI
+PUBLIC  Void kwUtlCalUlIpThrPut
+(
+KwCb                  *gCb,
+KwUlRbCb              *rbCb,
+Buffer                *pdu,
+U32                   ttiCnt
+)
+#else
+PUBLIC Void kwUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt)
+   KwCb                  *gCb;
+   KwUlRbCb              *rbCb;
+   Buffer                *pdu;
+   U32                   ttiCnt;
+#endif
+{
+   MsgLen        rlcSduSz = 0;  /*Holds length of Rlc Sdu*/
+   VOLATILE U32     startTime = 0;
+   TRC2(kwUtlCalUlIpThrPut)
+
+
+   /*starting Task*/
+   SStartTask(&startTime, PID_RLC_IP_TPT_INCVOL);
+
+   /*Check if UL IP throughput measurement is ON for this RB or not*/
+   if(KW_MEAS_IS_UL_IP_MEAS_ON_FOR_RB(gCb, rbCb) &&              
+         (TRUE  == rbCb->ueCb->isUlBurstActive) &&
+         (rbCb->ueCb->firstPacketTTI) &&
+         (ttiCnt != rbCb->ueCb->firstPacketTTI))
+   {
+      SFndLenMsg(pdu, &rlcSduSz);
+
+      rbCb->rbL2Cb.l2Sts[KW_L2MEAS_UL_IP]->ulIpThruput.volSummation += rlcSduSz;
+
+   }
+   /*stopping Task*/
+   SStopTask(startTime, PID_RLC_IP_TPT_INCVOL);
+} /* kwUtlCalUlIpThrPut */
+
+\f
+/**
+ *
+ * @brief Handler for L2 Measurement timer expiry.
+ *
+ *
+ * @b Description
+ *        This function is called when the l2 measurement timer expires. 
+ *        This function sends a consolidates the mesaurements taken during
+ *        this time and sends the confirm .
+ *
+ *  @param[in] measEvtCb    Measurement Event Control Block.
+ *
+ *
+ *  @return  S16
+ *      -# ROK
+ */
+
+#ifdef ANSI
+PUBLIC S16 kwUtlHdlL2TmrExp
+(
+KwCb          *gCb,
+KwL2MeasEvtCb *measEvtCb
+)
+#else
+PUBLIC S16 kwUtlHdlL2TmrExp(measEvtCb)
+KwCb          *gCb;
+KwL2MeasEvtCb *measEvtCb;
+#endif
+{
+   TRC3(kwUtlHdlL2TmrExp)
+
+#ifdef LTE_L2_MEAS_RLC
+   U16             qciIdx;
+   KwL2MeasCb     *measCb;
+   
+   /* Clean up the RB data structures */
+   if((measEvtCb->measCb.measType & LKW_L2MEAS_ACT_UE) &&
+      (measEvtCb->measCb.val.nonIpThMeas.numSamples))
+   {
+      measCb = &measEvtCb->measCb;
+
+      for(qciIdx = 0; qciIdx < measCb->val.nonIpThMeas.numQci;qciIdx++)
+      {
+         measCb->val.nonIpThMeas.measData[measCb->val.nonIpThMeas.qci[qciIdx]].actUe.numActvUe   +=   
+                     kwCb.kwL2Cb.numActUe[measCb->val.nonIpThMeas.qci[qciIdx]];
+         measCb->val.nonIpThMeas.measData[measCb->val.nonIpThMeas.qci[qciIdx]].actUe.sampOc++;
+      }
+      measEvtCb->val.nonIpThMeas.measCb.numSamples--;
+      kwStartTmr(gCb, (PTR)measEvtCb, KW_EVT_L2_TMR); 
+      RETVALUE(ROK);
+   }
+#endif
+
+   kwUtlSndUlL2MeasCfm(gCb, measEvtCb);
+
+   RETVALUE(ROK);
+} /* kwUtlHdlL2TmrExp */
+/**
+ *
+ * @brief Handler for Sending L2 Measurement confirm.
+ *
+ *
+ * @b Description
+ *        This function sends a consolidates the mesaurements taken during
+ *        this time and sends the confirm .
+ *
+ *  @param[in] measEvtCb    Measurement Event Control Block.
+ *
+ *
+ *  @return  S16
+ *      -# ROK
+ */
+
+#ifdef ANSI
+PUBLIC S16 kwUtlSndUlL2MeasCfm
+(
+KwCb                  *gCb,
+KwL2MeasEvtCb         *measEvtCb
+)
+#else
+PUBLIC S16 kwUtlSndUlL2MeasCfm(gCb, measEvtCb)
+KwCb                  *gCb;
+KwL2MeasEvtCb         *measEvtCb;
+#endif
+{
+   U32                     qciIdx;
+   KwL2MeasCb              *measCb;
+   KwL2MeasCfmEvt          measCfmEvt;
+
+   U64                     ulDataVol;
+   U64                     ulTime;
+   U16                     cntr;
+   /* Discard new changes starts */
+   U8                      qci = 0;
+   U32                     cfmIdx =0;
+   /* Discard new changes ends */
+
+   TRC3(kwUtlSndUlL2MeasCfm)
+
+   /* kw006.201 ccpu00120058 emoved 64 bit compilation warning */
+#ifndef ALIGN_64BIT
+   RLOG1(L_DEBUG,"kwUtlSndUlL2MeasCfm(transId(%ld))", measEvtCb->transId);
+#else
+   RLOG1(L_DEBUG,"kwUtlSndUlL2MeasCfm(transId(%d))", measEvtCb->transId);
+#endif
+
+   /* Clean up the RB data structures */
+   measCb = &measEvtCb->measCb;
+   
+   cmMemset((U8*)&measCfmEvt, 0, sizeof(KwL2MeasCfmEvt));
+   measCfmEvt.transId = measEvtCb->transId;
+
+   measCfmEvt.measType = measCb->measType;
+   measCfmEvt.status.status = LCM_PRIM_OK;
+   measCfmEvt.status.reason = LCM_REASON_NOT_APPL;
+   
+   if( measCb->measType & LKW_L2MEAS_UL_IP)
+   {
+      KwL2MeasCbUeMeasInfo *pUeInfoLstCb  = measCb->val.ipThMeas.ueInfoLst;
+      KwL2MeasCfmUeInfoLst *pUeInfoLstCfm = measCfmEvt.val.ipThMeas.ueInfoLst;
+      for(cntr = 0;(cntr < measCb->val.ipThMeas.numUes) && (cntr < gCb->genCfg.maxUe);cntr++)        
+      {
+         pUeInfoLstCfm[cfmIdx].numCfm = 0;
+         if (pUeInfoLstCb[cntr].isValid == TRUE)
+         {
+            pUeInfoLstCfm[cfmIdx].ueId = pUeInfoLstCb[cntr].ueId;
+            pUeInfoLstCfm[cfmIdx].cellId = pUeInfoLstCb[cntr].cellId;
+
+            for(qciIdx = 0; qciIdx < pUeInfoLstCb[cntr].numQci; qciIdx++)
+            {
+               qci = pUeInfoLstCb[cntr].qci[qciIdx];
+               pUeInfoLstCfm[cfmIdx].measCfm[pUeInfoLstCfm[cfmIdx].numCfm].qci = qci;
+
+               if(measCb->measType & LKW_L2MEAS_UL_IP)
+               {
+                  ulDataVol = pUeInfoLstCb[cntr].measData[qci].ulIpThruput.volSummation;
+                  ulTime = pUeInfoLstCb[cntr].measData[qci].ulIpThruput.timeSummation;
+                  if(0 == ulTime)
+                  {
+                     pUeInfoLstCfm[cfmIdx].measCfm[pUeInfoLstCfm[cfmIdx].numCfm].val.ipThrput.ulIpThPut = 0;
+                  }
+                  else
+                  {
+                     pUeInfoLstCfm[cfmIdx].measCfm[pUeInfoLstCfm[cfmIdx].numCfm].val.ipThrput.ulIpThPut = (ulDataVol / ulTime);
+
+                     /* Converting it to kbps */
+                     pUeInfoLstCfm[cfmIdx].measCfm[pUeInfoLstCfm[cfmIdx].numCfm].val.ipThrput.ulIpThPut *= 8;
+
+                  }
+                  /* Reset the values after reporting to Application */
+                  pUeInfoLstCb[cntr].measData[qci].ulIpThruput.volSummation = 0;
+                  pUeInfoLstCb[cntr].measData[qci].ulIpThruput.timeSummation = 0;
+               }
+               pUeInfoLstCfm[cfmIdx].numCfm++;
+            }
+            cfmIdx++;
+         }
+      }
+      measCfmEvt.val.ipThMeas.numUes = cfmIdx; 
+   }
+   KwMiLkwL2MeasCfm(&gCb->genCfg.lmPst, &measCfmEvt);
+   RETVALUE(ROK);
+} /* kwUtlSndUlL2MeasCfm */
+/**
+ *
+ * @brief Handler for Sending Negative confirm .
+ *
+ *
+  @b Description
+ *        This function is called when the l2 measurement cannot be started
+ *        This function sends  negative confirm for all the requests
+ *
+ * @param[in] gCb - RLC instance control block
+ * @param[in] measReqEvt    Measurement Req Structure
+ * @param[in] measCfmEvt  Confirmation to be sent to layer manager
+ *
+ *
+ *  @return  S16
+ *      -# ROK
+ */
+
+#ifdef ANSI
+PUBLIC S16 kwUtlSndUlL2MeasNCfm
+(
+KwCb           *gCb,
+KwL2MeasReqEvt *measReqEvt,
+KwL2MeasCfmEvt *measCfmEvt
+)
+#else
+PUBLIC S16 kwUtlSndUlL2MeasNCfm(gCb, measReqEvt, measCfmEvt)
+KwCb           *gCb;
+KwL2MeasReqEvt *measReqEvt;
+KwL2MeasCfmEvt *measCfmEvt;
+#endif
+{
+   TRC3(kwUtlSndUlL2MeasNCfm)
+
+   KwMiLkwL2MeasCfm(&gCb->genCfg.lmPst, measCfmEvt);
+   RETVALUE(ROK);
+} /* kwUtlSndL2MeasNCfm */
+
+#ifdef LTE_L2_MEAS_RLC
+/**
+ * @brief  Validates the measurement request parameters. 
+ *
+ * @details
+ *
+ *     Function :kwUtlValidateL2Meas 
+ *
+ *  @param[in]  measReqEvt L2 measurement request received from layer manager.
+ *  @param[out] measCfmEvt L2 measurement confirm to be prepared.
+ *  @param[out] lChId      List of LCh for the given Ue corresponding to QCIs
+                           given in measurement request.
+ *  @param[out] numLCh     Number of LCh in array lChId.
+ **/
+
+#ifdef ANSI
+PUBLIC S16 kwUtlValidateL2Meas
+(
+KwL2MeasReqEvt *measReqEvt,
+KwL2MeasCfmEvt *measCfmEvt,
+CmLteLcId      *lChId,
+U8             *numLCh
+)
+#else
+PUBLIC S16 kwUtlValidateL2Meas(measReqEvt, measCfmEvt, lChId, numLCh)
+KwL2MeasReqEvt *measReqEvt;
+KwL2MeasCfmEvt *measCfmEvt;
+CmLteLcId      *lChId;
+U8             *numLCh;
+#endif
+{
+   U8      measType;
+   S16     ret;
+   U8      qciIdx;
+   U8      qci;
+   U8      idx;
+   U8      *qciVal;
+   U8      numQci;
+   KwRbCb  *rbCb;
+
+   KwUeCb     *ueCb;
+   RbCb       **rbCbLst;
+   U8         rbIdx;
+   U8         lsbNibble = 0;
+   U8         msbNibble = 0;
+   U8         numFaild = 0;
+
+
+   TRC3(kwUtlValidateL2Meas)
+   
+   idx = 0;
+   rbCb = NULLP;
+   ret = ROK;
+   measType = measReqEvt->measReq.measType;
+   /* Check for the range of measType */
+   /* LKW_L2MEAS_DL_IP+ LKW_L2MEAS_UL_IP = 0x0030*/
+   if((measType == 0x00) ||
+       measType > 0x30)
+   {
+      measCfmEvt->transId = measReqEvt->transId;
+      measCfmEvt->measType = measType;
+      measCfmEvt->status.status = LCM_PRIM_NOK;
+      measCfmEvt->status.reason = LKW_CAUSE_INVALID_MEASTYPE;
+      RETVALUE(RFAILED);
+   }
+   /*User can either request for Active UE,*
+    *Dl delay, Dl discard, Uu Loss OR Dl ip throughput, Ul ip throughput. */
+   lsbNibble = measType & 0x0F;
+   msbNibble = measType & 0xF0;
+
+   if( (lsbNibble != 0) && (msbNibble != 0) )
+   {
+      measCfmEvt->transId = measReqEvt->transId;
+      measCfmEvt->measType = measType;
+      measCfmEvt->status.status = LCM_PRIM_NOK;
+      measCfmEvt->status.reason = LKW_CAUSE_INVALID_MEASTYPE;
+      RETVALUE(RFAILED);
+   }
+
+   /* Check for total maximum number of Measurement Control Block */
+   if(kwCb.kwL2Cb.kwNumMeas >= LKW_MAX_L2MEAS )
+   {
+      measCfmEvt->transId = measReqEvt->transId;
+      measCfmEvt->measType = measType;
+      measCfmEvt->status.status = LCM_PRIM_NOK;
+      measCfmEvt->status.reason = LKW_CAUSE_EXCEED_NUMMEAS;
+      RETVALUE(RFAILED);
+   }
+
+   /* Check that number of samples should be a non-zero value */
+   if(((measType & LKW_L2MEAS_ACT_UE) &&
+      (measReqEvt->measReq.val.nonIpThMeas.numSamples == 0)))
+   {
+      measCfmEvt->transId = measReqEvt->transId;
+      measCfmEvt->measType = measType;
+      measCfmEvt->status.status = LCM_PRIM_NOK;
+      measCfmEvt->status.reason = LKW_CAUSE_ZERO_NUMSAM;
+      RETVALUE(RFAILED);
+   }
+   /* Check that measurement period  should be completely divisible *
+    * number of sample.                                             */
+   if(((measType & LKW_L2MEAS_ACT_UE) &&
+      ((measReqEvt->measPeriod % 
+        measReqEvt->measReq.val.nonIpThMeas.numSamples) != 0)))
+   {
+      measCfmEvt->transId = measReqEvt->transId;
+      measCfmEvt->measType = measType;
+      measCfmEvt->status.status = LCM_PRIM_NOK;
+      measCfmEvt->status.reason = LKW_CAUSE_INVALID_NUMSAM;
+      RETVALUE(RFAILED);
+   }
+   {
+      numQci = measReqEvt->measReq.val.nonIpThMeas.numQci;
+      qciVal = measReqEvt->measReq.val.nonIpThMeas.qci;
+   }
+   /* Check whether qci is configured or not */
+   for(qciIdx = 0; qciIdx < numQci; qciIdx++)
+   {
+      qci = qciVal[qciIdx];
+      ret = cmHashListFind(&(kwCb.kwL2Cb.qciHlCp), 
+            (U8 *)&qci, (U16)sizeof(qci), 0, (PTR *)&rbCb);
+      if(ret != ROK)
+      {
+         measCfmEvt->val.nonIpThMeas.measCfm[measCfmEvt->val.nonIpThMeas.numCfm].qci = qci;
+         measCfmEvt->val.nonIpThMeas.numCfm++;
+
+      }
+   }
+   if(measCfmEvt->val.nonIpThMeas.numCfm > 0)
+   {
+      measCfmEvt->status.status = LCM_PRIM_NOK;
+      measCfmEvt->status.reason = LKW_CAUSE_INVALID_QCI;
+      measCfmEvt->measType = measType;
+      measCfmEvt->transId = measReqEvt->transId;
+      RETVALUE(RFAILED);
+   }
+   {
+      for(qciIdx = 0; qciIdx < numQci; qciIdx++)
+      {
+         if(kwCb.kwL2Cb.measOn[qci] & measReqEvt->measReq.measType)
+         {
+            /* measurement is already ongoing */
+            measCfmEvt->status.status = LCM_PRIM_NOK;
+            measCfmEvt->status.reason = LKW_CAUSE_MEAS_ALREADY_ENA;
+            measCfmEvt->val.nonIpThMeas.measCfm[measCfmEvt->val.nonIpThMeas.numCfm].qci = qci;
+            measCfmEvt->measType = measType;
+            measCfmEvt->val.nonIpThMeas.numCfm++;
+         }
+      }
+   }
+   if(measCfmEvt->val.nonIpThMeas.numCfm > 0)
+   {
+      measCfmEvt->transId = measReqEvt->transId;
+      RETVALUE(RFAILED);
+   }
+
+   RETVALUE(ROK);
+}/* kwUtlValidateL2Meas */
+#endif
+
+#ifdef ANSI
+PUBLIC S16 kwUtlValidateIpThL2Meas
+(
+KwL2MeasReqEvt *measReqEvt,
+KwL2MeasCfmEvt *measCfmEvt
+)
+#else
+PUBLIC S16 kwUtlValidateIpThL2Meas(measReqEvt, measCfmEvt)
+KwL2MeasReqEvt *measReqEvt;
+KwL2MeasCfmEvt *measCfmEvt;
+#endif
+{
+   U8      measType;
+   U8         lsbNibble = 0;
+   U8         msbNibble = 0;
+
+   TRC3(kwUtlValidateIpThL2Meas)
+   
+   measType = measReqEvt->measReq.measType;
+   /* Check for the range of measType */
+   /* LKW_L2MEAS_DL_IP+ LKW_L2MEAS_UL_IP = 0x0030*/
+   if((measType == 0x00) ||
+       measType > 0x30)
+   {
+      measCfmEvt->transId = measReqEvt->transId;
+      measCfmEvt->measType = measType;
+      measCfmEvt->status.status = LCM_PRIM_NOK;
+      measCfmEvt->status.reason = LKW_CAUSE_INVALID_MEASTYPE;
+      RETVALUE(RFAILED);
+   }
+   /*User can either request for Active UE,*
+    *Dl delay, Dl discard, Uu Loss OR Dl ip throughput, Ul ip throughput. */
+   lsbNibble = measType & 0x0F;
+   msbNibble = measType & 0xF0;
+
+   if( (lsbNibble != 0) && (msbNibble != 0) )
+   {
+      measCfmEvt->transId = measReqEvt->transId;
+      measCfmEvt->measType = measType;
+      measCfmEvt->status.status = LCM_PRIM_NOK;
+      measCfmEvt->status.reason = LKW_CAUSE_INVALID_MEASTYPE;
+      RETVALUE(RFAILED);
+   }
+   RETVALUE(ROK);
+}/* kwUtlValidateL2Meas */
+
+/**
+ *
+ * @brief Handler for resetting the RB data structures
+ *
+ *
+ * @b Description
+ *        This function resets the RB data structure after the expiry of 
+ *        measurement timer.
+ *
+ *  @param[in] measCb    Measurement Control Block.
+ *
+ *
+ *  @return  Void
+ */
+#ifdef ANSI
+
+PUBLIC Void kwUtlResetUlL2MeasInKwRb
+(
+KwCb       *gCb,
+KwL2MeasCb *measCb,
+U8             measType
+)
+#else
+PUBLIC Void kwUtlResetUlL2MeasInKwRb(measCb, measType)
+KwCb       *gCb;
+KwL2MeasCb *measCb;
+U8             measType;
+#endif
+{
+   U32           rbIdx;
+   U32           ueIdx;
+   U32           qciIdx;
+   KwUlUeCb         *ueCb = NULL;
+
+
+
+   if (measCb->measType & LKW_L2MEAS_UL_IP)
+   {
+      for(ueIdx = 0; ueIdx < measCb->val.ipThMeas.numUes; ueIdx++)
+      {           
+         if (measCb->val.ipThMeas.ueInfoLst[ueIdx].isValid == TRUE)
+         {
+            for (qciIdx =0; qciIdx < measCb->val.ipThMeas.ueInfoLst[ueIdx].numQci; qciIdx++)
+            {
+               if (measType & LKW_L2MEAS_UL_IP)
+               {
+                  measCb->val.ipThMeas.ueInfoLst[ueIdx].measData[qciIdx].ulIpThruput.volSummation = 0;
+                  measCb->val.ipThMeas.ueInfoLst[ueIdx].measData[qciIdx].ulIpThruput.timeSummation = 0;
+               }
+            }
+
+            if(ROK  != kwDbmFetchUlUeCb(gCb, measCb->val.ipThMeas.ueInfoLst[ueIdx].ueId,
+                     measCb->val.ipThMeas.ueInfoLst[ueIdx].cellId, &ueCb))
+            {
+               continue;
+            }
+
+            for (rbIdx = 0; rbIdx < KW_MAX_DRB_PER_UE; rbIdx++)
+            {
+               if (ueCb->drbCb[rbIdx])
+               {
+                  ueCb->drbCb[rbIdx]->rbL2Cb.measOn &= ~measType;
+               }
+            }
+         }
+      }
+   }
+} /* kwUtlResetUlL2MeasInKwRb */
+
+/**
+ *
+ * @brief Handler for storing address of MeasData in rbCb at right index
+ *
+ *
+ * @b Description
+ *        This function is called when LM sends measReq message to RLC.
+ *
+ *  @param[in] 
+ *  @param[out] 
+ *  @param[in] 
+ *
+ *
+ *  @return  S16
+ *      -# ROK
+ */
+#ifdef ANSI
+PUBLIC Void kwUtlPlcMeasDatInL2Sts
+(
+KwL2Cntr       *measData, 
+KwL2MeasRbCb   *rbL2Cb,
+U8             measType
+)
+#else
+PUBLIC Void kwUtlPlcMeasDatInL2Sts(measData, rbL2Cb, measType)
+KwL2Cntr       *measData; 
+KwL2MeasRbCb   *rbL2Cb;
+U8             measType;
+#endif
+{
+   TRC3(kwUtlPlcMeasDatInL2Sts)
+   
+   /* We should check the number of measType in the request. This can be done 
+    * by looking at each bit in the measType. Also store the measData in the 
+    * correct index of l2Sts in RbCb.
+    * */
+
+    if(measType & LKW_L2MEAS_ACT_UE)
+    {
+         rbL2Cb->l2Sts[KW_L2MEAS_ACT_UE] = measData;
+    }
+    if(measType & LKW_L2MEAS_UU_LOSS)
+    {
+         rbL2Cb->l2Sts[KW_L2MEAS_UU_LOSS] = measData;
+    }
+    if(measType & LKW_L2MEAS_DL_IP )
+    {
+         rbL2Cb->l2Sts[KW_L2MEAS_DL_IP] = measData;
+    }
+    if(measType & LKW_L2MEAS_UL_IP)
+    {
+         rbL2Cb->l2Sts[KW_L2MEAS_UL_IP] = measData;
+    }
+    if(measType & LKW_L2MEAS_DL_DISC)
+    {
+         rbL2Cb->l2Sts[KW_L2MEAS_DL_DISC] = measData;
+    }
+    if(measType & LKW_L2MEAS_DL_DELAY)
+    {
+         rbL2Cb->l2Sts[KW_L2MEAS_DL_DELAY] = measData;
+    }
+}/* End of kwUtlPlcMeasDatInL2Sts */
+#endif /* LTE_L2_MEAS */
+
+/**
+ *
+ * @brief Store the UL buffer in hashList  
+ *
+ *
+ * @b Description
+ *
+ *   Use the SN % binSize as key and store the received UL buffer
+ *  @param[in] recBufLst       List CP array
+ *  @param[in] recBuf          received buffer
+ *  @param[in] sn              sn of the received buffer 
+ *
+ *
+ *  @return  Void
+ */
+#ifdef ANSI
+PUBLIC Void kwUtlStoreRecBuf 
+(
+CmLListCp        *recBufLst,
+KwAmRecBuf       *recBuf,
+KwSn              sn
+)
+#else
+PUBLIC Void kwUtlStoreRecBuf(recBufLst, recBuf, sn)
+CmLListCp        *recBufLst;
+KwAmRecBuf       *recBuf;
+KwSn              sn;
+#endif
+{
+   U32             hashKey; 
+
+   TRC3(kwUtlStoreRecBuf)
+   
+   hashKey = (sn % KW_RCV_BUF_BIN_SIZE ); 
+   recBuf->lnk.node = (PTR)recBuf;
+   cmLListAdd2Tail(&(recBufLst[hashKey]), &recBuf->lnk);
+
+   RETVOID;
+} /* kwUtlStoreRecBuf */
+
+/**
+ *
+ * @brief Retrieve the UL buffer from the list
+ *
+ *
+ * @Description
+ *
+ *   Use the SN % binSize as key and retrieve the UL buffer
+ *  @param[in] recBufLst       List CP array
+ *  @param[in] sn              sn of the received buffer 
+ *
+ *
+ *  @return  Void
+ */
+#ifdef ANSI
+PUBLIC KwAmRecBuf* kwUtlGetRecBuf 
+(
+CmLListCp        *recBufLst,
+KwSn             sn
+)
+#else
+PUBLIC KwAmRecBuf* kwUtlGetRecBuf(recBufLst, sn)
+CmLListCp        *recBufLst;
+KwSn             sn;
+#endif
+{
+   U32                 hashKey; 
+   CmLListCp           *recBufLstCp;
+   KwAmRecBuf          *recBuf;
+   CmLList             *node = NULLP;
+
+   TRC3(kwUtlGetRecBuf)
+
+   hashKey = (sn % KW_RCV_BUF_BIN_SIZE ); 
+   recBufLstCp = &recBufLst[hashKey];
+   CM_LLIST_FIRST_NODE(recBufLstCp, node);
+   while(node)
+   {
+      recBuf = (KwAmRecBuf *) node->node;
+      if(recBuf->amHdr.sn == sn)
+      {
+         RETVALUE(recBuf);
+      }
+      CM_LLIST_NEXT_NODE(recBufLstCp, node);
+   }
+   RETVALUE(NULLP);
+} /* kwUtlStoreRecBuf */
+/**
+ *
+ * @brief Delete the UL buffer from the list
+ *
+ *
+ * @Description
+ *
+ *   Use the SN % binSize as key and retrieve the UL buffer
+ *  @param[in] recBufLst       List CP array
+ *  @param[in] sn              sn of the received buffer 
+ *
+ *
+ *  @return  Void
+ */
+#ifdef ANSI
+PUBLIC Void kwUtlDelRecBuf 
+(
+CmLListCp        *recBufLst,
+KwAmRecBuf       *recBuf,
+KwCb              *gCb                              
+)
+#else
+PUBLIC Void kwUtlDelRecBuf(recBufLst, recBufi, gCb)
+CmLListCp        *recBufLst;
+KwAmRecBuf       *recBuf;
+KwCb             *gCb;                              
+#endif
+{
+   U32                 hashKey; 
+   CmLListCp           *recBufLstCp;
+
+   TRC3(kwUtlDelRecBuf)
+
+   hashKey = (recBuf->amHdr.sn % KW_RCV_BUF_BIN_SIZE ); 
+   recBufLstCp = &recBufLst[hashKey];
+   cmLListDelFrm(recBufLstCp, &recBuf->lnk);
+   KW_FREE_WC(gCb, recBuf, sizeof(KwAmRecBuf));
+
+   RETVOID;
+} /* kwUtlDelRecBuf */
+
+
+
+
+/********************************************************************30**
+         End of file
+**********************************************************************/