[Epic-ID: ODUHIGH-516][Task-ID: ODUHIGH-532] RIC Subscription Delete Req/Rsp API...
[o-du/l2.git] / src / 5gnrsch / sch.c
index 85f6d76..ace885e 100644 (file)
 #include "rg_sch_inf.x"         /* typedefs for Scheduler */
 #include "mac_sch_interface.h"
 #include "sch.h"
+#include "sch_tmr.h"
 #include "sch_utils.h"
 #include "sch_fcfs.h"
 #include "sch_slice_based.h"
 
-/**
- * @brief Task Initiation function. 
- *
- * @details
- *
- *     Function : schActvInit
- *     
- *     This function is supplied as one of parameters during MAC's 
- *     task registration. MAC will invoke this function once, after
- *     it creates and attaches this TAPA Task to a system task.
- *     
- *  @param[in]  Ent Entity, the entity ID of this task.     
- *  @param[in]  Inst Inst, the instance ID of this task.
- *  @param[in]  Region Region, the region ID registered for memory 
- *              usage of this task.
- *  @param[in]  Reason Reason.
- *  @return  int
- *      -# ROK
- **/
-uint8_t schActvInit(Ent entity, Inst instId, Region region, Reason reason)
-{
-   Inst inst = (instId  - SCH_INST_START);
-
-   /* Initialize the MAC TskInit structure to zero */
-   memset ((uint8_t *)&schCb[inst], 0, sizeof(schCb));
-
-   /* Initialize the MAC TskInit with received values */
-   schCb[inst].schInit.ent = entity;
-   schCb[inst].schInit.inst = inst;
-   schCb[inst].schInit.region = region;
-   schCb[inst].schInit.pool = 0;
-   schCb[inst].schInit.reason = reason;
-   schCb[inst].schInit.cfgDone = FALSE;
-   schCb[inst].schInit.acnt = FALSE;
-   schCb[inst].schInit.usta = FALSE;
-   schCb[inst].schInit.trc = FALSE;
-   schCb[inst].schInit.procId = ODU_GET_PROCID();
-
-   return ROK;
-} /* schActvInit */
-
 /**
  * @brief Scheduler All Apis initialized. 
  *
@@ -150,28 +110,32 @@ uint8_t SchInstCfg(RgCfg *cfg, Inst  dInst)
 
    schCb[inst].schInit.region = cfg->s.schInstCfg.genCfg.mem.region;
    schCb[inst].schInit.pool = cfg->s.schInstCfg.genCfg.mem.pool;
-   schCb[inst].genCfg.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
 #ifdef LTE_ADV
    schCb[inst].genCfg.forceCntrlSrbBoOnPCel =  cfg->s.schInstCfg.genCfg.forceCntrlSrbBoOnPCel;
    schCb[inst].genCfg.isSCellActDeactAlgoEnable =  cfg->s.schInstCfg.genCfg.isSCellActDeactAlgoEnable;
 #endif
    schCb[inst].genCfg.startCellId    = cfg->s.schInstCfg.genCfg.startCellId;
 
+   schCb[inst].schTimersInfo.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
    /* Initialzie the timer queue */   
-   memset(&schCb[inst].tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
+   memset(&schCb[inst].schTimersInfo.tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
    /* Initialize the timer control point */
-   memset(&schCb[inst].tmrTqCp, 0, sizeof(CmTqCp));
-   schCb[inst].tmrTqCp.tmrLen = RGSCH_TQ_SIZE;
+   memset(&schCb[inst].schTimersInfo.tmrTqCp, 0, sizeof(CmTqCp));
+   schCb[inst].schTimersInfo.tmrTqCp.tmrLen = SCH_TQ_SIZE;
 
    /* SS_MT_TMR needs to be enabled as schActvTmr needs instance information */
    /* Timer Registration request to system services */
-   if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst, (int)schCb[inst].genCfg.tmrRes, schActvTmr) != ROK)
+   if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst, (int)schCb[inst].schTimersInfo.tmrRes, schActvTmr) != ROK)
    {
-      DU_LOG("\nERROR  -->  SCH : SchInstCfg(): Failed to "
-           "register timer.");
+      DU_LOG("\nERROR  -->  SCH : SchInstCfg(): Failed to register timer.");
       return (LCM_REASON_MEM_NOAVAIL);
    }   
-              
+
+   /* Initialize statistics related configurations */
+   memset(&schCb[inst].statistics, 0, sizeof(SchStatistics));
+   cmLListInit(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList);
+   cmLListInit(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList);
+
    /* Set Config done in TskInit */
    schCb[inst].schInit.cfgDone = TRUE;
    DU_LOG("\nINFO   -->  SCH : Scheduler gen config done");
@@ -381,7 +345,7 @@ void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
    int8_t slotIdx, symbIdx;
 
    periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
-   cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, schCellCfg->numerology))/1000;
+   cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, cell->numerology))/1000;
    cell->slotFrmtBitMap = 0;
    schFillSlotConfig(cell, schCellCfg->tddCfg);
    for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
@@ -434,7 +398,7 @@ void fillSsbStartSymb(SchCellCb *cellCb)
 {
    uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
 
-   scs = cellCb->cellCfg.scsCommon;
+   scs = cellCb->cellCfg.ssbScs;
 
    memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
    symbIdx = 0;
@@ -496,6 +460,7 @@ void fillSsbStartSymb(SchCellCb *cellCb)
  **/
 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
 {
+   uint16_t scsInKhz = 0;
    SchCellCb *cell= NULLP;
    SCH_ALLOC(cell, sizeof(SchCellCb));
    if(!cell)
@@ -506,7 +471,11 @@ uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
 
    cell->cellId = schCellCfg->cellId; 
    cell->instIdx = inst;
-   switch(schCellCfg->numerology)
+   scsInKhz = convertScsEnumValToScsVal(schCellCfg->ssbScs);
+   
+   /*Ref : 3GPP 38.211 Table 4.2-1: SCS = (2 ^ numerology * 15kHz)*/
+   cell->numerology = log2(scsInKhz/BASE_SCS);
+   switch(cell->numerology)
    {
       case SCH_NUMEROLOGY_0:
         {
@@ -534,7 +503,7 @@ uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
         }
         break;
       default:
-        DU_LOG("\nERROR  -->  SCH : Numerology %d not supported", schCellCfg->numerology);
+        DU_LOG("\nERROR  -->  SCH : Numerology %d not supported", cell->numerology);
    }
 #ifdef NR_TDD
    schInitTddSlotCfg(cell, schCellCfg);   
@@ -710,13 +679,7 @@ uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchC
    pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
    /* Storing pdschCfg pointer here. Required to access pdsch config while
       fillig up pdcch pdu */
-   SCH_ALLOC(pdcch->dci.pdschCfg, sizeof(PdschCfg));
-   if(pdcch->dci.pdschCfg == NULLP)
-   {
-      DU_LOG("\nERROR  -->  SCH : Memory allocation failed in %s ", __func__);
-      return RFAILED;
-   }
-   pdsch = pdcch->dci.pdschCfg; 
+   pdsch = &pdcch->dci.pdschCfg; 
 
    /* fill the PDSCH PDU */
    uint8_t cwCount = 0;
@@ -738,7 +701,7 @@ uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchC
    pdsch->numLayers                          = 1;
    pdsch->transmissionScheme                 = 0;
    pdsch->refPoint                           = 0;
-   pdsch->dmrs.dlDmrsSymbPos                 = 4; /* Bitmap value 00000000000100 i.e. using 3rd symbol for PDSCH DMRS */
+   pdsch->dmrs.dlDmrsSymbPos                 = DL_DMRS_SYMBOL_POS; 
    pdsch->dmrs.dmrsConfigType                = 0; /* type-1 */
    pdsch->dmrs.dlDmrsScramblingId            = pci;
    pdsch->dmrs.scid                          = 0;
@@ -801,7 +764,7 @@ uint8_t SchProcCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
    cellCb->macInst = pst->srcInst;
 
    /* derive the SIB1 config parameters */
-   ret = fillSchSib1Cfg(schCellCfg->numerology, schCellCfg->dlBandwidth, cellCb->numSlots,
+   ret = fillSchSib1Cfg(cellCb->numerology, schCellCfg->dlBandwidth, cellCb->numSlots,
         &(schCellCfg->pdcchCfgSib1), &(cellCb->sib1SchCfg), schCellCfg->phyCellId,
         schCellCfg->dlCfgCommon.schFreqInfoDlSib.offsetToPointA, schCellCfg->sib1PduLen);
    
@@ -975,7 +938,6 @@ void deleteSchCellCb(SchCellCb *cellCb)
          SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport*sizeof(Snssai*));
       }
    }
-   SCH_FREE(cellCb->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg, sizeof(PdschCfg));
 
    for(uint16_t idx =0; idx<MAX_SFN; idx++)
    {
@@ -1336,7 +1298,7 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
       if(ssbOccasion && sib1Occasion)
       {
          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
-         broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg->pdschFreqAlloc.numPrb -1;
+         broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
       }
       else if(ssbOccasion)
       {
@@ -1345,8 +1307,8 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
       }
       else if(sib1Occasion)
       {
-         broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg->pdschFreqAlloc.startPrb;
-         broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg->pdschFreqAlloc.numPrb -1;
+         broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.startPrb;
+         broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
       }
 
       /* Iterate through all free PRB blocks */
@@ -1424,6 +1386,10 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
          return RFAILED;
       }
    }
+   
+   /* Update statistics of PRB usage if stats calculation is enabled */
+   if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
+      prbAlloc->numPrbAlloc += numPrb;
 
    /* Update the remaining number for free PRBs */
    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
@@ -1558,6 +1524,10 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
       }
    }
 
+   /* Update statistics of PRB usage if stats calculation is enabled */
+   if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
+      prbAlloc->numPrbAlloc += numPrb;
+
    /* Update the remaining number for free PRBs */
    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
 
@@ -1614,7 +1584,7 @@ uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_
       {
          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
-                          cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg->pdschFreqAlloc.numPrb -1;
+                          cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
       }
       else if(ssbOccasion)
       {
@@ -1623,8 +1593,8 @@ uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_
       }
       else if(sib1Occasion)
       {
-         reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg->pdschFreqAlloc.startPrb;
-         reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg->pdschFreqAlloc.numPrb -1;
+         reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.startPrb;
+         reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
       }
       else
       {
@@ -1727,150 +1697,105 @@ void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
    MacMessageRouter(&rspPst, (void *)&sliceCfgRsp);
 
 }
+
 /*******************************************************************************
  *
- * @brief fill slice configuration response
+ * @brief This function is used to store or modify the slice configuration Sch DB
  *
  * @details
  *
- *    Function : fillSliceCfgRsp
+ *    Function : addOrModifySliceCfgInSchDb 
  *
  *    Functionality:
- *     fill slice configuration response
+ *     function is used to store or modify the slice configuration Sch DB
  *
- * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
+ * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
+ * SchSliceCfgRsp cfgRsp, uint8_t count
  *
  * @return
  *        ROK - Success
  *        RFAILED - Failure
  *
  * ********************************************************************************/
-uint8_t fillSliceCfgRsp(bool sliceRecfg, SchSliceCfg *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq, SchSliceCfgRsp *schSliceCfgRsp, uint8_t *count)
+uint8_t addSliceCfgInSchDb(CmLListCp *sliceCfgInDb, SchRrmPolicyOfSlice *cfgReq)
 {
-   bool sliceFound = false;
-   uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0;
+   SchRrmPolicyOfSlice *sliceToStore;
 
-   schSliceCfgRsp->numSliceCfgRsp  = schSliceCfgReq->numOfConfiguredSlice;
-   SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp, schSliceCfgRsp->numSliceCfgRsp * sizeof(SliceRsp*));
-   if(schSliceCfgRsp->listOfSliceCfgRsp == NULLP)
+   SCH_ALLOC(sliceToStore, sizeof(SchRrmPolicyOfSlice));
+   if(sliceToStore)
    {
-      DU_LOG("\nERROR  --> SCH : Memory allocation failed at fillSliceCfgRsp");
-      return RFAILED;
+      memcpy(&sliceToStore->snssai, &cfgReq->snssai, sizeof(Snssai));  
+      memcpy(&sliceToStore->rrmPolicyRatioInfo, &cfgReq->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));  
+      addNodeToLList(sliceCfgInDb, sliceToStore, NULL);
    }
-
-   for(cfgIdx = 0; cfgIdx<schSliceCfgRsp->numSliceCfgRsp ; cfgIdx++)
+   else
    {
-      sliceFound = false;
-      /* Here comparing the slice cfg request with the slice stored in cellCfg */
-      if(sliceRecfg != true)
-      {
-         for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
-         {
-            for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
-            {
-               if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai)))
-               {
-                  (*count)++;
-                  sliceFound = true;
-                  break;
-               }
-            }
-            if(sliceFound == true)
-            {
-               break;
-            }
-         }
-      }
-      else
-      {
-         /* Here comparing the slice cfg request with the slice stored in SchDb */
-         if(storedSliceCfg->listOfSlices)
-         {
-            for(sliceIdx = 0; sliceIdx<storedSliceCfg->numOfSliceConfigured; sliceIdx++)
-            {
-               if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, &storedSliceCfg->listOfSlices[sliceIdx]->snssai,\
-                        sizeof(Snssai)))
-               {
-                  (*count)++;
-                  sliceFound = true;
-                  break;
-               }
-            }
-         }
-      }
-
-      SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx], sizeof(SliceRsp));
-      if(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx] == NULLP)
-      {
-         DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in fillSliceCfgRsp");
-         return RFAILED;
-      }
-
-
-      schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
-      if(sliceFound == true)
-         schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_OK;
-      else
-      {
-         schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_NOK;
-         schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->cause  = SLICE_NOT_FOUND;
-      }
+      DU_LOG("\nERROR  -->  SCH : Memory allocation failed in addOrModifySliceCfgInSchDb");
+      return RFAILED;
    }
    return ROK;
 }
 
 /*******************************************************************************
  *
- * @brief This function is used to store the slice configuration Sch DB
+ * @brief fill slice configuration response
  *
  * @details
  *
- *    Function : addSliceCfgInSchDb 
+ *    Function : fillSliceCfgRsp
  *
  *    Functionality:
- *     function is used to store the slice configuration Sch DB
+ *     fill slice configuration response
  *
- * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
- * SchSliceCfgRsp cfgRsp, uint8_t count
+ * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
  *
  * @return
  *        ROK - Success
  *        RFAILED - Failure
  *
  * ********************************************************************************/
-uint8_t addSliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
+uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq)
 {
-   uint8_t cfgIdx = 0, sliceIdx = 0; 
-   
-   if(count)
-   {
-      storeSliceCfg->numOfSliceConfigured = count;
-      SCH_ALLOC(storeSliceCfg->listOfSlices, storeSliceCfg->numOfSliceConfigured * sizeof(SchRrmPolicyOfSlice*));
-      if(storeSliceCfg->listOfSlices == NULLP)
-      {
-         DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
-         return RFAILED;
-      }
+   SchMacRsp sliceFound;
+   uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0, ret =ROK;
+   SchSliceCfgRsp schSliceCfgRsp;
 
-      for(cfgIdx = 0; cfgIdx<storeSliceCfg->numOfSliceConfigured; cfgIdx++)
+   for(cfgIdx = 0; cfgIdx<schSliceCfgReq->numOfConfiguredSlice; cfgIdx++)
+   {
+      sliceFound = RSP_NOK;
+      /* Here comparing the slice cfg request with the slice stored in cellCfg */
+      for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
       {
-         if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
+         for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
          {
-            SCH_ALLOC(storeSliceCfg->listOfSlices[sliceIdx], sizeof(SchRrmPolicyOfSlice));
-            if(storeSliceCfg->listOfSlices[sliceIdx] == NULLP)
+            /* If we find the SliceCfgReq's SNSSAI in CellCb's SNSSAI DB, we mark this slice as configured and add it to Sch's DB. */ 
+            if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai)))
             {
-               DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
-               return RFAILED;
+               if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
+               {
+                  sliceFound = RSP_OK;
+                  schSliceCfgRsp.cause = SUCCESSFUL;
+               }
+               else
+               {
+                  DU_LOG("\nERROR  --> SCH : Failed to store slice configuration in SchDb");
+                  schSliceCfgRsp.cause = RESOURCE_UNAVAILABLE;
+                  ret = RFAILED;
+               }
+               plmnIdx = MAX_PLMN;
+               break;
             }
-
-            memcpy(&storeSliceCfg->listOfSlices[sliceIdx]->snssai, &cfgReq->listOfSlices[sliceIdx]->snssai, sizeof(Snssai));
-            memcpy(&storeSliceCfg->listOfSlices[sliceIdx]->rrmPolicyRatioInfo, &cfgReq->listOfSlices[sliceIdx]->rrmPolicyRatioInfo,
-                      sizeof(SchRrmPolicyRatio));
-            sliceIdx++;
          }
       }
+      
+      if((sliceFound == RSP_NOK) && (schSliceCfgRsp.cause != RESOURCE_UNAVAILABLE))
+         schSliceCfgRsp.cause = SLICE_NOT_FOUND;
+      
+      schSliceCfgRsp.snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
+      schSliceCfgRsp.rsp    = sliceFound;
+      SchSendSliceCfgRspToMac(inst, schSliceCfgRsp);
    }
-   return ROK;
+   return ret;
 }
 
 /*******************************************************************************
@@ -1930,9 +1855,8 @@ void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
  * ********************************************************************************/
 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
 {
-   uint8_t count = 0;
+   uint8_t ret = ROK;
    Inst   inst = pst->dstInst - SCH_INST_START;
-   SchSliceCfgRsp sliceCfgRsp;
 
    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
    if(schSliceCfgReq)
@@ -1940,77 +1864,22 @@ uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
       if(schSliceCfgReq->listOfSlices)
       {
          /* filling the slice configuration response of each slice */
-         if(fillSliceCfgRsp(false, NULLP, schCb[inst].cells[0], schSliceCfgReq, &sliceCfgRsp, &count) != ROK)
+         if(fillSliceCfgRsp(inst, &schCb[inst].sliceCfg, schCb[inst].cells[0], schSliceCfgReq) != ROK)
          {
             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
-            return RFAILED;
-         }
-
-         if(addSliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceCfgReq, sliceCfgRsp, count) != ROK)
-         {
-            DU_LOG("\nERROR  -->  SCH : Failed to add slice cfg in sch database");
-            return RFAILED;
+            ret = RFAILED;
          }
          freeSchSliceCfgReq(schSliceCfgReq);
-         SchSendSliceCfgRspToMac(inst, sliceCfgRsp);
       }
    }
    else
    {
       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
+      ret = RFAILED;
    }
-   return ROK;
+   return ret;
 }
 
-/*******************************************************************************
- *
- * @brief This function is used to store the slice reconfiguration Sch DB
- *
- * @details
- *
- *    Function : modifySliceCfgInSchDb 
- *
- *    Functionality:
- *     function is used to store the slice re configuration Sch DB
- *
- * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
- *
- * @return
- *        ROK - Success
- *        RFAILED - Failure
- *
- * ********************************************************************************/
-uint8_t modifySliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceRecfgReq *recfgReq, SchSliceRecfgRsp recfgRsp, uint8_t count)
-{
-   uint8_t cfgIdx = 0, sliceIdx = 0; 
-
-   if(count)
-   {
-      if(storeSliceCfg->listOfSlices == NULLP)
-      {
-         DU_LOG("\nINFO  -->  SCH : Memory allocation failed in modifySliceCfgInSchDb");
-         return RFAILED;
-      }
-
-      for(cfgIdx = 0; cfgIdx<recfgReq->numOfConfiguredSlice; cfgIdx++)
-      {
-         if(recfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
-         {
-            for(sliceIdx = 0; sliceIdx<storeSliceCfg->numOfSliceConfigured; sliceIdx++)
-            {
-               if(!memcmp(&storeSliceCfg->listOfSlices[sliceIdx]->snssai, &recfgReq->listOfSlices[cfgIdx]->snssai, sizeof(Snssai)))
-               {
-                  memcpy(&storeSliceCfg->listOfSlices[sliceIdx]->rrmPolicyRatioInfo, &recfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo,
-                           sizeof(SchRrmPolicyRatio));
-                  break;
-               }
-            }
-         }
-      }
-   }
-   freeSchSliceCfgReq(recfgReq);
-   return ROK;
-}
 /*******************************************************************************
  *
  * @brief This function is used to send Slice re Cfg rsp to MAC
@@ -2037,6 +1906,61 @@ void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
    
    MacMessageRouter(&rspPst, (void *)&schSliceRecfgRsp);
 }
+
+/*******************************************************************************
+ *
+ * @brief fill slice configuration response
+ *
+ * @details
+ *
+ *    Function : fillSliceRecfgRsp
+ *
+ *    Functionality: fill slice reconfiguration response
+ *
+ * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
+ *
+ * @return
+ *        ROK - Success
+ *        RFAILED - Failure
+ *
+ * ********************************************************************************/
+
+uint8_t fillSliceRecfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchSliceRecfgReq *schSliceRecfgReq)
+{
+   SchMacRsp sliceFound;
+   uint8_t cfgIdx = 0;
+   SchRrmPolicyOfSlice *rrmPolicyOfSlices;
+   SchSliceRecfgRsp schSliceRecfgRsp;
+
+   for(cfgIdx = 0; cfgIdx<schSliceRecfgReq->numOfConfiguredSlice; cfgIdx++)
+   {
+      sliceFound = RSP_NOK;
+      /* Here comparing the slice recfg request with the StoredSliceCfg */
+      CmLList *sliceCfg = storedSliceCfg->first;
+
+      while(sliceCfg)
+      {
+         rrmPolicyOfSlices = (SchRrmPolicyOfSlice*)sliceCfg->node;
+         
+         if(rrmPolicyOfSlices && (memcmp(&schSliceRecfgReq->listOfSlices[cfgIdx]->snssai, &(rrmPolicyOfSlices->snssai), sizeof(Snssai)) == 0))
+         {
+            memcpy(&rrmPolicyOfSlices->rrmPolicyRatioInfo, &schSliceRecfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
+            sliceFound = RSP_OK;
+            break;
+         }
+         sliceCfg = sliceCfg->next;
+      }
+
+      schSliceRecfgRsp.snssai = schSliceRecfgReq->listOfSlices[cfgIdx]->snssai;
+      schSliceRecfgRsp.rsp    = sliceFound;
+      if(schSliceRecfgRsp.rsp == RSP_OK)
+         schSliceRecfgRsp.cause = SUCCESSFUL;
+      else
+         schSliceRecfgRsp.cause = SLICE_NOT_FOUND;
+      SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
+   }
+   return ROK;
+}
 /*******************************************************************************
  *
  * @brief This function is used to store the slice reconfiguration Sch DB
@@ -2057,9 +1981,8 @@ void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
  * ********************************************************************************/
 uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
 {
-   uint8_t count = 0;
+   uint8_t ret = ROK;
    Inst   inst = pst->dstInst - SCH_INST_START;
-   SchSliceRecfgRsp schSliceRecfgRsp;
 
    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
    if(schSliceRecfgReq)
@@ -2067,26 +1990,20 @@ uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
       if(schSliceRecfgReq->listOfSlices)
       {
          /* filling the slice configuration response of each slice */
-         if(fillSliceCfgRsp(true, &schCb[inst].sliceCfg, NULLP, schSliceRecfgReq, &schSliceRecfgRsp, &count) != ROK)
+         if(fillSliceRecfgRsp(inst, &schCb[inst].sliceCfg, schSliceRecfgReq) != ROK)
          {
             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
-            return RFAILED;
-         }
-         
-         /* Modify the slice configuration stored in schCb */
-         if(modifySliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceRecfgReq, schSliceRecfgRsp, count) != ROK)
-         {
-            DU_LOG("\nERROR  -->  SCH : Failed to modify slice cfg of SchDb");
-            return RFAILED;
+            ret = RFAILED;
          }
-         SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
+         freeSchSliceCfgReq(schSliceRecfgReq);
       }
    }
    else
    {
       DU_LOG("\nERROR  -->  SCH : Received SchSliceRecfgReq is NULL");
+
    }
-   return ROK;
+   return ret;
 }
 
 /****************************************************************************
@@ -2394,6 +2311,787 @@ RgMngmt       *cfm
    return;
 }
 
+/*******************************************************************
+ *
+ * @brief Processes DL CQI ind from MAC
+ *
+ * @details
+ *
+ *    Function : SchProcDlCqiInd
+ *
+ *    Functionality:
+ *       Processes DL CQI ind from MAC
+ *
+ * @params[in] 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchProcDlCqiInd(Pst *pst, SchDlCqiInd *dlCqiInd)
+{
+   uint8_t  ret = ROK;
+   uint16_t ueId = 0, cellIdx = 0;
+   SchUeCb *ueCb = NULLP;
+   SchCellCb *cell = NULLP;
+   Inst  inst = pst->dstInst-SCH_INST_START;   
+
+   if(!dlCqiInd)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): CQI Ind is empty");
+      ret = RFAILED;
+   }
+   else
+   {
+      GET_CELL_IDX(dlCqiInd->cellId, cellIdx);
+      cell = schCb[inst].cells[cellIdx];
+      if(cell == NULLP)
+      { 
+         DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): cell Id[%d] not found", dlCqiInd->cellId);
+         ret = RFAILED;
+      }
+      else
+      {
+         if(cell->cellId == dlCqiInd->cellId)
+         {
+            GET_UE_ID(dlCqiInd->crnti, ueId);
+            ueCb = &cell->ueCb[ueId-1];
+            if(ueCb->crnti != dlCqiInd->crnti)
+            {
+               DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): UeCb for received crnti[%d] not found", dlCqiInd->crnti);
+               ret = RFAILED;
+            }
+            else
+            {
+               /*TODO: complete the processing of DL CQI Ind*/ 
+            }
+         }
+         else
+         {
+            DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): Received cell Id[%d] from MAC is not matching with CellID[%d] in SCH Cb",\
+                    dlCqiInd->cellId, cell->cellId);
+            ret = RFAILED;
+         }
+      }
+   }
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Processes UL CQI ind from MAC
+ *
+ * @details
+ *
+ *    Function : SchProcUlCqiInd
+ *
+ *    Functionality:
+ *       Processes UL CQI ind from MAC
+ *
+ * @params[in] 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchProcUlCqiInd(Pst *pst, SchUlCqiInd *ulCqiInd)
+{
+   uint8_t  ret = ROK;
+   uint16_t ueId = 0, cellIdx = 0;
+   SchUeCb *ueCb = NULLP;
+   SchCellCb *cell = NULLP;
+   Inst  inst = pst->dstInst-SCH_INST_START;   
+
+   if(!ulCqiInd)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): CQI Ind is empty");
+      ret = RFAILED;
+   }
+   else
+   {
+      GET_CELL_IDX(ulCqiInd->cellId, cellIdx);
+      cell = schCb[inst].cells[cellIdx];
+      if(cell == NULLP)
+      { 
+         DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): cell Id[%d] not found", ulCqiInd->cellId);
+         ret = RFAILED;
+      }
+      else
+      {
+         if(cell->cellId == ulCqiInd->cellId)
+         {
+            GET_UE_ID(ulCqiInd->crnti, ueId);
+            ueCb = &cell->ueCb[ueId-1];
+            if(ueCb->crnti != ulCqiInd->crnti)
+            {
+               DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): UeCb for received crnti[%d] not found",ulCqiInd->crnti);
+               ret = RFAILED;
+            }
+            else
+            {
+               /*TODO: complete the processing of UL CQI Ind*/ 
+            }
+         }
+         else
+         {
+            DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): Received cell Id[%d] from MAC is not matching with CellId[%d] in SCH Cb",\
+                    ulCqiInd->cellId, cell->cellId);
+            ret = RFAILED;
+         }
+      }
+   }
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Processes PHR ind from MAC
+ *
+ * @details
+ *
+ *    Function : SchProcPhrInd
+ *
+ *    Functionality:
+ *       Processes PHR ind from MAC
+ *
+ * @params[in] 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
+{
+   uint8_t  ret = ROK;
+   uint16_t ueId = 0, cellIdx = 0;
+   SchUeCb *ueCb = NULLP;
+   SchCellCb *cell = NULLP;
+   Inst  inst = pst->dstInst-SCH_INST_START;   
+
+   if(!schPhrInd)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): PHR is empty");
+      ret = RFAILED;
+   }
+   else
+   {
+      GET_CELL_IDX(schPhrInd->cellId, cellIdx);
+      cell = schCb[inst].cells[cellIdx];
+      if(cell == NULLP)
+      { 
+         DU_LOG("\nERROR  -->  SCH : schProcPhrInd(): cell Id[%d] is not found", schPhrInd->cellId);
+         ret = RFAILED;
+      }
+      else
+      {
+         if(cell->cellId == schPhrInd->cellId)
+         {
+            GET_UE_ID(schPhrInd->crnti, ueId);
+            ueCb = &cell->ueCb[ueId-1];
+            if(ueCb->crnti != schPhrInd->crnti)
+            {
+               DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): UeCb for received crnti[%d] not found",schPhrInd->crnti);
+               ret = RFAILED;
+            }
+            else
+            {
+               /*TODO: complete the processing of PHR Ind*/ 
+            }
+         }
+         else
+         {
+            DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): Mismatch between Received cell Id[%d] from MAC and CellID[%d] in SCH CB ",\
+                    schPhrInd->cellId, cell->cellId);
+            ret = RFAILED;
+         }
+      }
+   }
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Fill and send statistics response to MAC
+ *
+ * @details
+ *
+ *    Function :  SchSendStatsRspToMac
+ *
+ *    Functionality: Fill and send statistics response to MAC
+ *
+ * @params[in]  Inst inst, SchMacRsp result
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
+{
+   Pst rspPst;
+   uint8_t ret = ROK;
+   SchStatsRsp  *schStatsRsp;
+
+   DU_LOG("\nINFO   --> SCH : Filling statistics response");
+   SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
+   if(schStatsRsp == NULLP)
+   {
+      DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
+      return RFAILED;
+   }
+   memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
+   memset(statsRsp, 0, sizeof(SchStatsRsp));
+
+   /* Filling response post */
+   memset(&rspPst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(rspPst, inst);
+   rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
+
+   ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
+   if(ret == RFAILED)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
+      return ret;
+   }
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Rejects all statistics group requested by MAC
+ *
+ * @details
+ *
+ *    Function : SchRejectAllStats
+ *
+ *    Functionality: Add all statistics group received in statistics
+ *       request from MAC, to Reject-Stats-Group-List in statistics
+ *       response to MAC
+ *
+ * @params[in]  Statistics request from MAC
+ *              Cause of rejection
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
+{
+   uint8_t grpIdx = 0;
+   SchStatsRsp schStatsRsp;
+
+   memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
+
+   /* Copying all stats group from stats request to stats response */
+   schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
+   for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
+   {
+      schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
+      schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
+   }
+   schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
+
+   return SchSendStatsRspToMac(&schStatsRsp);
+}
+
+/*******************************************************************
+ *
+ * @brief Add active KPI pointers to KPI-Active-List
+ *
+ * @details
+ *
+ *    Function : schAddToKpiActiveList
+ *
+ *    Functionality: For each active statistics group for which timer
+ *       is running, add its KPI pointer to KPI-Active-List.
+ *       Use case :
+ *       When it is needed to update a KPI parameters, we need not
+ *       traverse all statistics group and all KPIs within a group
+ *       to get the specific KPI pointer to be updated.
+ *       Instead, we can traverse through KPI-Active-List and update
+ *       all entries in this list.
+ *
+ * @params[in]  Statistics request from MAC
+ *              Cause of rejection
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schAddToKpiActiveList(Inst inst, SchStatsGrp *grpInfo)
+{
+   CmLList  *node = NULLP;
+
+   /* If DL Total PRB Usage configured for this stats group, add to list */
+   if(grpInfo->kpiStats.dlTotalPrbUsage)
+   {
+      SCH_ALLOC(node, sizeof(CmLList));
+      if(node)
+      {
+         node->node = (PTR)grpInfo->kpiStats.dlTotalPrbUsage; 
+         cmLListAdd2Tail(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, node);
+      }
+   }
+
+   /* If UL Total PRB Usage configured for this stats group, add to list */
+   node = NULLP;
+   if(grpInfo->kpiStats.ulTotalPrbUsage)
+   {
+      SCH_ALLOC(node, sizeof(CmLList));
+      if(node)
+      {
+         node->node = (PTR)grpInfo->kpiStats.ulTotalPrbUsage; 
+         cmLListAdd2Tail(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, node);
+      }
+   }
+
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Processes Statistics Request from MAC
+ *
+ * @details
+ *
+ *    Function : SchProcStatsReq
+ *
+ *    Functionality:
+ *
+ *     This function process the statistics request from MAC:
+ *     [Step 1] Basic validation. If fails, all stats group in stats request are
+ *     rejected.
+ *     [Step 2] If basic validations passed, traverse all stats group and
+ *     validate each measurement types in each group.
+ *     [Step 3] If any measurement type validation fails in a group, that group
+ *     is not configured and it is added to stats-group-rejected-list in
+ *     sch-stats-response message.
+ *     [Step 4] If a group passes all validation, it is added to SCH database.
+ *     A timer is started for this group. And the group is added to 
+ *     stats-group-accepted-list in sch-stats-response message.
+ *     [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
+ *     and stats-group-accepted-list.
+ *
+ * @params[in] Post structure
+ *             Statistics Request from MAC 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
+{
+   uint8_t grpIdx = 0, reqGrpIdx = 0, reqMeasIdx = 0;
+   Inst    inst = pst->dstInst - SCH_INST_START;
+   bool    measTypeInvalid;
+   CauseOfResult cause;
+   SchStatsInfo  *statsInfo = NULLP;
+   SchStatsGrpInfo *grpInfo = NULLP;
+   SchStatsGrp *grpInfoDb = NULLP;
+   SchStatsRsp schStatsRsp;
+
+   DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
+
+   if(statsReq == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Received Null pointer");
+      return RFAILED;
+   }
+
+   /* [Step 1] Basic validation. If fails, all stats group in stats request are rejected */
+   
+   /* If maximum number of statistics already configured */
+   if(schCb[inst].statistics.numOfStatsCfgd >= MAX_NUM_STATS_CFG)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Maximum number of statistics configured. \
+            Cannot process new request.");
+      SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
+      SCH_FREE(statsReq, sizeof(SchStatsReq));
+      return RFAILED;
+   }
+
+   memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
+
+   /* [Step 2] Traverse all stats group and validate each measurement types in each group */
+   statsInfo = &schCb[inst].statistics.statsInfoList[schCb[inst].statistics.numOfStatsCfgd];
+   statsInfo->numStatsGroup = 0;
+   for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
+   {
+       measTypeInvalid = false;
+       grpInfo = &statsReq->statsGrpList[reqGrpIdx];
+       grpInfoDb = &statsInfo->statsGrpList[grpIdx];
+       for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
+       {
+          switch(grpInfo->statsList[reqMeasIdx])
+          {
+             case SCH_DL_TOTAL_PRB_USAGE:
+                {
+                   /* Allocate memory */
+                   SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+                   if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
+                   {
+                      DU_LOG("\nERROR   -->  SCH : Memory allocation failed for dlTotalPrbUsage in \
+                            SchProcStatsReq()");
+                      measTypeInvalid = true;
+                      cause = RESOURCE_UNAVAILABLE;
+                   }
+                   break;
+                }
+
+             case SCH_UL_TOTAL_PRB_USAGE:
+                {
+                   /* Allocate memory */
+                   SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+                   if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
+                   {
+                      DU_LOG("\nERROR   -->  SCH : Memory allocation failed for dlTotalPrbUsage in \
+                            SchProcStatsReq()");
+                      measTypeInvalid = true;
+                      cause = RESOURCE_UNAVAILABLE;
+                   }
+                   break;
+                }
+
+             default:
+                {
+                   DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Invalid measurement type [%d]", \
+                         grpInfo->statsList[reqMeasIdx]);
+                   measTypeInvalid = true;
+                   cause = PARAM_INVALID;
+                   break;
+                }
+          }
+
+          /* [Step 3 a] If any measurement type validation fails in a group, that group
+           *  is not configured */
+          if(measTypeInvalid)
+          {
+             SCH_FREE(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+             SCH_FREE(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+             memset(grpInfoDb, 0, sizeof(SchStatsGrp));   
+             break;
+          }
+       }
+   
+       /* [Step 4] If a group passes all validation, it is added to SCH database.
+        * A timer is started for this group. And the group is added to
+        * stats-group-accepted-list in sch-stats-response message. */
+       if(!measTypeInvalid)
+       {
+          /* Add this group's configured KPIs to list of Active KPIs */
+          if(schAddToKpiActiveList(inst, grpInfoDb) == ROK)
+          {
+             grpInfoDb->schInst = inst;
+             grpInfoDb->subscriptionId = statsReq->subscriptionId;
+             grpInfoDb->groupId = grpInfo->groupId;
+             grpInfoDb->periodicity = grpInfo->periodicity;
+
+
+             /* Start timer */
+             cmInitTimers(&(grpInfoDb->periodTimer), 1);
+             schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
+
+             schStatsRsp.statsGrpAcceptedList[schStatsRsp.numGrpAccepted] = grpInfo->groupId;
+             schStatsRsp.numGrpAccepted++;
+             grpIdx++;
+          }
+          else
+          {
+            memset(grpInfoDb, 0, sizeof(SchStatsGrp));
+          }
+       }
+       else
+       {
+          /* [Step 3 b] The rejected group is added to stats-group-rejected-list in
+           * sch-stats-response message */
+          memset(grpInfoDb, 0, sizeof(SchStatsGrp));
+          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
+          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = cause;
+          schStatsRsp.numGrpRejected++;
+       }
+   }
+   statsInfo->numStatsGroup = grpIdx;
+   if(statsInfo->numStatsGroup)
+   {
+      schCb[inst].statistics.numOfStatsCfgd++;
+   }
+   else
+   {
+      memset(statsInfo, 0, sizeof(SchStatsInfo));
+   }
+   schStatsRsp.subscriptionId = statsReq->subscriptionId;
+
+   SCH_FREE(statsReq, sizeof(SchStatsReq));
+
+   /* [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
+    * and stats-group-accepted-list. */
+   SchSendStatsRspToMac(&schStatsRsp);
+
+   return ROK;
+} /* End of SchProcStatsReq */
+
+/*******************************************************************
+ *
+ * @brief Fill and send statistics indication to MAC
+ *
+ * @details
+ *
+ *    Function :  SchSendStatsIndToMac
+ *
+ *    Functionality: Fill and send statistics indication to MAC
+ *
+ * @params[in]  SCH Instance
+ *              Measurement Type
+ *              Measurement Value
+ *              Size of value parameter
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd  *statsInd)
+{
+   Pst pst;
+   uint8_t ret = ROK;
+
+#ifdef DEBUG_PRINT
+   DU_LOG("\nDEBUG  --> SCH : Filling statistics indication");
+#endif
+
+   /* Filling post structure */
+   memset(&pst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(pst, inst);
+   pst.event = EVENT_STATISTICS_IND_TO_MAC;
+
+   ret = MacMessageRouter(&pst, (void *)statsInd);
+   if(ret == RFAILED)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
+   }
+   return ret;
+}
+
+/**
+ * @brief Handler to process Timer expiry of DL Total PRB Usage calculation 
+ *
+ * @param[in] cb        Control block depending on the type of the timer event.
+ * @param[in] tmrEvnt   Timer event to be started
+ *
+ * @return  Bool indicating whether the timer is running or not
+ *      -# ROK
+ *      -# RFAILED
+*/
+double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
+{
+   double percentageOfTotalPrbUsed = 0;
+
+   if(dlTotalPrbUsage->totalPrbAvailForTx)
+      percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
+   
+   memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+
+   return percentageOfTotalPrbUsed;
+}
+
+/**
+ * @brief Handler to check if the timer is running
+ *
+ * @param[in] cb        Control block depending on the type of the timer event.
+ * @param[in] tmrEvnt   Timer event to be started
+ *
+ * @return  Bool indicating whether the timer is running or not
+ *      -# ROK
+ *      -# RFAILED
+*/
+uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
+{
+   double percentageOfTotalPrbUsed = 0;
+
+   if(ulTotalPrbUsage->totalPrbAvailForTx)
+      percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
+
+   memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+
+   return percentageOfTotalPrbUsed;
+}
+
+/**
+ * @brief Calculates statistics in a group and sends
+ *          statistics indication for this group
+ *
+ * @param[in] Statistics group info
+ *
+ * @return
+ *      -# ROK
+ *      -# RFAILED
+*/
+uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
+{
+   uint8_t measStatsIdx = 0;
+   SchStatsInd  statsInd;
+
+   memset(&statsInd, 0, sizeof(SchStatsInd));
+   statsInd.subscriptionId = grpInfo->subscriptionId;
+   statsInd.groupId = grpInfo->groupId;
+
+   if(grpInfo->kpiStats.dlTotalPrbUsage)
+   {
+      statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;  
+      statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);   
+      measStatsIdx++;
+   }
+   
+   if(grpInfo->kpiStats.ulTotalPrbUsage)
+   {
+      statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;  
+      statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);   
+      measStatsIdx++;
+   }
+   
+   statsInd.numStats = measStatsIdx;
+
+   return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
+}
+
+/*******************************************************************
+ *
+ * @brief Fill and send Statistics Delete Response to MAC
+ *
+ * @details
+ *
+ *    Function :  SchSendStatsDeleteRspToMac
+ *
+ *    Functionality: Fill and send Statistics Delete Response to MAC
+ *
+ * @params[in]  
+ *       Statistics Delete Request from MAC
+ *       Statistics Delete result
+ *       Cause of response
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchSendStatsDeleteRspToMac(SchStatsDeleteReq *statsDeleteReq, SchMacRsp rsp, CauseOfResult cause)
+{
+   Pst rspPst;
+   uint8_t ret = ROK;
+   SchStatsDeleteRsp  *schStatsDeleteRsp;
+
+   DU_LOG("\nINFO   --> SCH : Filling Statistics Delete Response");
+   SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
+   if(schStatsDeleteRsp == NULLP)
+   {
+      DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsDeleteRspToMac()");
+      return RFAILED;
+   }
+   
+   schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
+   schStatsDeleteRsp->rsp=rsp;
+   schStatsDeleteRsp->cause=cause;
+   /* Filling response post */
+   memset(&rspPst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(rspPst, inst);
+   rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC;
+
+   ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp);
+   if(ret == RFAILED)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchSendStatsDeleteRspToMac(): Failed to send Statistics Response");
+      return ret;
+   }
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Delete statistics information 
+ *
+ * @details
+ *
+ *    Function : deleteStatsInfo 
+ *
+ *    Functionality:
+ *    Delete statistics information
+ *
+ * @params[in] 
+ *             Instance
+ *             Subscription id 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t deleteStatsInfo(Inst inst, uint64_t subscriptionId)
+{
+   bool statsFound=false;
+   uint8_t idx=0, statsGrpIdx=0;
+   SchStatsGrp *statsGrpInfo=NULLP;
+
+   if(schCb[inst].statistics.numOfStatsCfgd)
+   {
+      for(idx=0;idx<schCb[inst].statistics.numOfStatsCfgd; idx++)
+      {
+         for(statsGrpIdx=0;statsGrpIdx<schCb[inst].statistics.statsInfoList[idx].numStatsGroup; statsGrpIdx++)
+         {
+            statsGrpInfo = &schCb[inst].statistics.statsInfoList[idx].statsGrpList[statsGrpIdx];
+            if(statsGrpInfo->subscriptionId ==subscriptionId)
+            {
+               SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+               SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+               if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
+               {
+                  schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
+               }
+               memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
+               statsFound = true;
+            }
+         }
+      }
+   }
+
+   if(statsFound ==false)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Statistics information is not present");
+      return RFAILED;
+   }
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Processes Statistics Delete Request from MAC
+ *
+ * @details
+ *
+ *    Function : SchProcStatsDeleteReq
+ *
+ *    Functionality:
+ *     This function process the statistics delete request from MAC:
+ *
+ * @params[in] Post structure
+ *             Statistics Delete Request from MAC
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
+{
+   uint8_t ret =ROK;
+   Inst    inst = pst->dstInst - SCH_INST_START;
+
+   DU_LOG("\nINFO   -->  SCH : Received Statistics Delete Request from MAC");
+
+   if(statsDeleteReq == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Received Null pointer");
+      return RFAILED;
+   }
+
+   ret = deleteStatsInfo(inst, statsDeleteReq->subscriptionId);
+   if(ret == ROK)
+   {
+      SchSendStatsDeleteRspToMac(statsDeleteReq, RSP_OK, SUCCESSFUL);
+   }
+   else
+   {
+      SchSendStatsDeleteRspToMac(statsDeleteReq, RSP_NOK, STATS_ID_NOT_FOUND);
+   }
+   SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
+
+   return ret;
+} /* End of SchProcStatsDeleteReq */
+
 /**********************************************************************
   End of file
  **********************************************************************/