[Epic-ID: ODUHIGH-538][Issue-ID: ODUHIGH-563] Fixes to read SCTP and EGTP configurati...
[o-du/l2.git] / src / 5gnrsch / sch.c
index 85f6d76..8279bf6 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);   
@@ -626,7 +595,7 @@ uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchC
    uint8_t mValue = 0;
    uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
    uint8_t slotIndex = 0;
-   uint8_t FreqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
+   uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
    uint16_t tbSize = 0;
    uint8_t ssbIdx = 0;
    PdcchCfg *pdcch;
@@ -686,8 +655,8 @@ uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchC
    pdcch->coresetCfg.durationSymbols = numSymbols;
    
    /* Fill Bitmap for PRBs in coreset */
-   fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), FreqDomainResource);
-   covertFreqDomRsrcMapToIAPIFormat(FreqDomainResource, pdcch->coresetCfg.freqDomainResource);
+   fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), freqDomainResource);
+   memcpy(pdcch->coresetCfg.freqDomainResource, freqDomainResource, FREQ_DOM_RSRC_SIZE);
 
    pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
    pdcch->coresetCfg.regBundleSize = 6;    /* spec-38.211 sec 7.3.2.2 */
@@ -696,27 +665,21 @@ uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchC
    pdcch->coresetCfg.shiftIndex = pci;
    pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
    pdcch->numDlDci = 1;
-   pdcch->dci.rnti = SI_RNTI;
-   pdcch->dci.scramblingId = pci;
-   pdcch->dci.scramblingRnti = 0;
-   pdcch->dci.cceIndex = 0;
-   pdcch->dci.aggregLevel = 4;
-   pdcch->dci.beamPdcchInfo.numPrgs = 1;
-   pdcch->dci.beamPdcchInfo.prgSize = 1;
-   pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
-   pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
-   pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
-   pdcch->dci.txPdcchPower.beta_pdcch_1_0= 0;
-   pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
+   pdcch->dci[0].rnti = SI_RNTI;
+   pdcch->dci[0].scramblingId = pci;
+   pdcch->dci[0].scramblingRnti = 0;
+   pdcch->dci[0].cceIndex = 0;
+   pdcch->dci[0].aggregLevel = 4;
+   pdcch->dci[0].beamPdcchInfo.numPrgs = 1;
+   pdcch->dci[0].beamPdcchInfo.prgSize = 1;
+   pdcch->dci[0].beamPdcchInfo.digBfInterfaces = 0;
+   pdcch->dci[0].beamPdcchInfo.prg[0].pmIdx = 0;
+   pdcch->dci[0].beamPdcchInfo.prg[0].beamIdx[0] = 0;
+   pdcch->dci[0].txPdcchPower.beta_pdcch_1_0= 0;
+   pdcch->dci[0].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[0].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);
    
@@ -819,9 +782,8 @@ uint8_t SchProcCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
    offset = coresetIdxTable[coreset0Idx][3];
    fillCoresetFeqDomAllocMap(((cellCb->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA - offset)/6), \
                                   (numRbs/6), freqDomainResource);
-   covertFreqDomRsrcMapToIAPIFormat(freqDomainResource, \
-      cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc);
-
+   memcpy(cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc,\
+               freqDomainResource,FREQ_DOM_RSRC_SIZE);
    /* Fill K0 - K1 table for common cfg*/ 
    BuildK0K1Table(cellCb, &cellCb->k0K1InfoTbl, true, cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon,
                    pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
@@ -966,16 +928,15 @@ void deleteSchCellCb(SchCellCb *cellCb)
 
    for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
    {
-      if(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai)
+      if(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai)
       {
-         for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
+         for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
          {
-            SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai));
+            SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai));
          }
-         SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport*sizeof(Snssai*));
+         SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices*sizeof(Snssai*));
       }
    }
-   SCH_FREE(cellCb->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg, sizeof(PdschCfg));
 
    for(uint16_t idx =0; idx<MAX_SFN; idx++)
    {
@@ -1336,7 +1297,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[0].pdschCfg.pdschFreqAlloc.numPrb -1;
       }
       else if(ssbOccasion)
       {
@@ -1345,8 +1306,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[0].pdschCfg.pdschFreqAlloc.startPrb;
+         broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
       }
 
       /* Iterate through all free PRB blocks */
@@ -1424,6 +1385,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 +1523,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 +1583,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[0].pdschCfg.pdschFreqAlloc.numPrb -1;
       }
       else if(ssbOccasion)
       {
@@ -1623,8 +1592,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[0].pdschCfg.pdschFreqAlloc.startPrb;
+         reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
       }
       else
       {
@@ -1727,150 +1696,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].suppSliceList.numSupportedSlices; 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].suppSliceList.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 +1854,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 +1863,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 +1905,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 +1980,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 +1989,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 +2310,1267 @@ 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]  Pointer to the prb usage info link list
+ *              Pointer to the stats ccnfig which we need to add
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo)
+{
+   CmLList  *node = NULLP;
+
+   SCH_ALLOC(node, sizeof(CmLList));
+   if(node)
+   {
+      node->node = kpiStatsInfo; 
+      cmLListAdd2Tail(kpiList, node);
+      return ROK;
+   }
+   DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
+   return RFAILED;
+}
+
+ /*******************************************************************
+ *
+ * @brief add the stats group information in statistics's statsGrpList
+ *
+ * @details
+ *
+ *    Function : schAddToStatsGrpList
+ *
+ *    Functionality: add the stats group information in statsGrpList
+ *    [Step 1] - Allocating the memory for the stats group in which 
+ *          we need to fill into the list as a node.
+ *    [Step 2] - If allocation is successful then start traversing 
+ *          each measurment cfg index of received group info.
+ *       [Step 2.1] Validate all measurements. If validation succeeds, go
+ *       to [step 2.2]. Otherwise, reject the stats group and go to step 3.
+ *       [Step 2.2] Add each KPI/measurementCfg into activeKpiList one by one.
+ *       If it fails for any KPI, reject the whole statsGrp and go to step 3..
+ *       [Step 2.3] Fill other group related information
+ *       [Step 2.4] Initialise and start timer
+ *       [Step 2.5] Once all validation and configuration is successful, add
+ *       statsGrp node into statistic's StatsGrpList.
+ *          [Step 2.5.1] If node successfully added to the list, then 
+ *             fill the group related info in stats rsp's accepted list.
+ *          [Step 2.5.2] Else goto step 3
+ *    [Step 3] - If failed fill the group related info in stats rsp's 
+ *          rejected list.
+ *
+ * @params[in]  
+ *          Inst
+ *          Pointer to the stats rsp
+ *          Subscription Id
+ *          Stats Grp Info which needs to be store in the list
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+
+uint8_t schAddToStatsGrpList(Inst inst, struct schStatsRsp *statsRsp, uint64_t subscriptionId, SchStatsGrpInfo *grpInfo)
+{
+   uint8_t ret =ROK;
+   uint8_t grpIdx=0;
+   uint8_t reqMeasIdx=0;
+   CauseOfResult cause;
+   bool measTypeInvalid=false;
+   CmLList *statsGrpNode=NULLP; 
+   SchStatsGrp *grpInfoDb = NULLP;
+   
+   /* Step 1 */
+   SCH_ALLOC(grpInfoDb, sizeof(SchStatsGrp));
+   if(grpInfoDb == NULLP)
+   {
+      DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
+      cause = RESOURCE_UNAVAILABLE;
+      ret = RFAILED;
+   }
+   else
+   {
+      /* Step 2 */
+      for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
+      {
+         /* Step 2.1 */
+         switch(grpInfo->statsList[reqMeasIdx])
+         {
+            case SCH_DL_TOTAL_PRB_USAGE:
+               {
+                  SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+                  if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
+                  {
+                     DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
+                     measTypeInvalid = true;
+                     cause = RESOURCE_UNAVAILABLE;
+                     break;
+                  }
+                  break;
+               }
+
+            case SCH_UL_TOTAL_PRB_USAGE:
+               {
+                  SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+                  if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
+                  {
+                     DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
+                     measTypeInvalid = true;
+                     cause = RESOURCE_UNAVAILABLE;
+                     break;
+                  }
+                  break;
+               }
+
+            default:
+               {
+                  DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Invalid measurement type [%d]", \
+                        grpInfo->statsList[reqMeasIdx]);
+                  measTypeInvalid = true;
+                  cause = PARAM_INVALID;
+                  break;
+               }
+         }
+
+         if(measTypeInvalid)
+         {
+            ret =RFAILED;
+            break;
+         }
+      }
+
+      while(measTypeInvalid==false)
+      {
+         if(grpInfoDb->kpiStats.dlTotalPrbUsage)
+         {
+            /* Step 2.2 */
+            if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR)grpInfoDb->kpiStats.dlTotalPrbUsage)!=ROK)
+            {
+               DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
+               cause = RESOURCE_UNAVAILABLE;
+               ret =RFAILED;
+               break;
+            }
+         }
+
+         if(grpInfoDb->kpiStats.ulTotalPrbUsage)
+         {
+            /* Step 2.2 */
+            if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK)
+            {
+               DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
+               cause = RESOURCE_UNAVAILABLE;
+               ret =RFAILED;
+               break;
+            }
+         }
+
+         /* Step 2.3 */
+         grpInfoDb->schInst = inst;
+         grpInfoDb->groupId = grpInfo->groupId;
+         grpInfoDb->periodicity = grpInfo->periodicity;
+         grpInfoDb->subscriptionId = subscriptionId;
+
+         /* Step 2.4 */
+         cmInitTimers(&(grpInfoDb->periodTimer), 1);
+         schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
+
+         /* Step 2.5 */
+         SCH_ALLOC(statsGrpNode, sizeof(CmLList));
+         if(statsGrpNode)
+         {
+            /* Step 2.5.1 */
+            statsGrpNode->node = (PTR) grpInfoDb;
+            cmLListAdd2Tail(&schCb[inst].statistics.statsGrpList, statsGrpNode);
+            statsRsp->statsGrpAcceptedList[statsRsp->numGrpAccepted] = grpInfo->groupId;
+            statsRsp->numGrpAccepted++;
+            grpIdx++;
+            ret =  ROK;
+            break;
+         }
+         else
+         {
+            /* Step 2.5.2 */
+            DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
+            cause = RESOURCE_UNAVAILABLE;
+            ret  = RFAILED;
+            break;
+         }
+      }
+   }
+
+   if(ret != ROK)
+   {
+      /* Step 3 */
+      if(grpInfoDb)
+      {
+         deleteStatsGrpInfo(inst, grpInfoDb);      
+         SCH_FREE(grpInfoDb, sizeof(SchStatsGrp));
+      }
+      statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].groupId = grpInfo->groupId;
+      statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].cause = cause;
+      statsRsp->numGrpRejected++;
+      return RFAILED;
+   }
+   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.
+ *     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)
+{
+   bool allocFailed = false;
+   uint8_t grpIdx = 0, reqGrpIdx = 0;
+   SchStatsGrpInfo *grpInfo = NULLP;
+   SchStatsRsp schStatsRsp;
+   Inst inst = pst->dstInst - SCH_INST_START;
+
+   DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
+
+   if(statsReq == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Received Null pointer");
+      return RFAILED;
+   }
+
+   /*Step -1*/
+   if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP)
+   {
+      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*/
+   for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
+   {
+      grpInfo = &statsReq->statsGrpList[reqGrpIdx];
+      /*Step -3 */
+      if(allocFailed  == true)
+      {
+         schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
+         schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
+         schStatsRsp.numGrpRejected++;
+      }
+      else
+      {
+         /*Step -4 */
+         if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
+         {
+            DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Failed to fill the stats group list");
+            if((schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].groupId == grpInfo->groupId &&\
+                     (schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)))
+            { 
+               allocFailed = true;
+            }
+         }
+      }
+   }
+
+   schStatsRsp.subscriptionId = statsReq->subscriptionId;
+   SCH_FREE(statsReq, sizeof(SchStatsReq));
+   
+   /*Step -5 */
+   SchSendStatsRspToMac(&schStatsRsp);
+
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @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 Delete node from active kpi list
+ *
+ * @details
+ *
+ *    Function :deleteNodeFrmKpiList 
+ *
+ *    Functionality:
+ *    Delete statistics group
+ *
+ * @params[in]
+ *           Kpi list from which a node needs to be deleted
+ *           Nodes info which a node needs to be deleted
+ * @return void
+ * ****************************************************************/
+
+void deleteNodeFrmKpiList(CmLListCp *kpiList, PTR kpiNodeInfoToDel)
+{
+   CmLList *kpiNode=NULLP;
+
+   CM_LLIST_FIRST_NODE(kpiList, kpiNode);
+   while(kpiNode)
+   {
+      if(kpiNode->node == kpiNodeInfoToDel)
+      {
+         cmLListDelFrm(kpiList, kpiNode);
+         SCH_FREE(kpiNode, sizeof(CmLList));
+         break;
+      }
+      kpiNode = kpiNode->next;
+   }
+
+}
+
+/*******************************************************************
+ *
+ * @brief Delete statistics group info
+ *
+ * @details
+ *
+ *    Function : deleteStatsGrpInfo
+ *
+ *    Functionality:
+ *    Delete statistics group info
+ *
+ * @params[in]
+ *           Inst
+ *           Stats Grp info
+ * @return void
+ *
+ * ****************************************************************/
+void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo)
+{
+   if(statsGrpInfo)
+   {
+      if(statsGrpInfo->kpiStats.dlTotalPrbUsage)
+      {
+         deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR) statsGrpInfo->kpiStats.dlTotalPrbUsage);
+         SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+      }
+
+      if(statsGrpInfo->kpiStats.ulTotalPrbUsage)
+      {
+         deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR) statsGrpInfo->kpiStats.ulTotalPrbUsage);
+         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));
+   }
+}
+
+/*******************************************************************
+ *
+ * @brief Delete statistics group Node
+ *
+ * @details
+ *
+ *    Function : deleteStatsGrpNode
+ *
+ *    Functionality:
+ *    Delete statistics group node
+ *
+ * @params[in]
+ *           Inst
+ *           Stats Grp Node
+ * @return void
+ *
+ * ****************************************************************/
+void deleteStatsGrpNode(Inst inst, CmLList *grpNode)
+{
+   SchStatsGrp *statsGrpInfo=NULLP;
+
+   if(grpNode)
+   {
+      statsGrpInfo = (SchStatsGrp*)grpNode->node;
+      deleteStatsGrpInfo(inst, statsGrpInfo);      
+      memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
+      SCH_FREE(grpNode->node, sizeof(SchStatsGrp));
+      SCH_FREE(grpNode, sizeof(CmLList));
+   }
+}
+
+/******************************************************************
+ *
+ * @brief Deletion of node from statistics group list
+ *
+ * @details
+ *
+ *    Function : deleteFromStatsGrpList
+ *
+ *    Functionality: Deletion of node from statistics group list
+ *    [Step 1]: Traverse each and every node of stats group list
+ *    stored in the database
+ *    [Step 2]: Check if the node's subscription id is same 
+ *    as the subscription id received. If same then go to step 3
+ *    else move to the next node of the list.
+ *    [Step 3]: If deleteAllGrp == true, then delete the node and 
+ *    move to the next node of the list.
+ *    [Step 4]: If deleteAllGrp != true, then check if the node's group
+ *    id is same as group id received then delete the node and mark the 
+ *    status found true else move to the next node of the list.
+ *    [Step 5]: Once the traversing complete,  
+ *    if deleteAllGrp is true, then return successful rsp;
+ *    else if status found is true, then return  successful rsp;
+ *    else return failure.
+ * @params[in] 
+ *           Inst
+ *           Stats Grp List 
+ *           Subscription Id
+ *           Group Id
+ *           boolen of deleteAllGrp
+ * @return void
+ *
+ * ****************************************************************/
+uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t  subscriptionId, uint8_t  groupId, bool deleteAllGrp)
+{
+   bool statsFound=false;
+   SchStatsGrp *statsGrpInfo=NULLP;
+   CmLList *grpNode=NULLP;
+
+   /* [Step 1] */
+   CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
+   while(grpNode)
+   {
+      statsGrpInfo = (SchStatsGrp*)grpNode->node;
+
+      /* [Step 2] */
+      if(statsGrpInfo->subscriptionId== subscriptionId) 
+      {
+         if(deleteAllGrp == true)
+         {
+            /* [Step 3] */
+            cmLListDelFrm(statsGrpList, grpNode);
+            deleteStatsGrpNode(inst, grpNode);
+         }
+         else
+         {
+            /* [Step 4] */
+            if(statsGrpInfo->groupId== groupId) 
+            {
+               cmLListDelFrm(statsGrpList, grpNode);
+               deleteStatsGrpNode(inst, grpNode);
+               statsFound = true;
+            }
+         }
+      }
+      CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
+   }
+
+   /* [Step 5] */
+   if(deleteAllGrp == true)
+   {
+      return ROK;
+   }
+   else
+   {
+      if(statsFound == true)
+         return ROK;
+   }
+   return RFAILED;
+}
+
+/*******************************************************************
+ *
+ * @brief Delete statistics information 
+ *
+ * @details
+ *
+ *    Function : deleteStatsInfo 
+ *
+ *    Functionality:
+ *   Delete statistics information base on numStatsGroup 
+ *   Info- If numStatsGroup = 0' indicates the Deletion procedure triggered by
+ *   'SUBS_DELETION_REQ' wherein all the groups of this particular
+ *   Subscription has to be removed 
+ *   else when numStatsGroup != 0 then this is
+ *   for SUBS_MOD_REQ's actionToBeDeleted wherein particular action(s) has
+ *   to be removed thus need to pass groupId belonging to that subscription
+ *   which has to be deleted.'
+ *
+ *   [Step-1] If numStatsGroup = 0, Deletion of all stats group belonging to
+ *   received subscription Id.
+ *   [Step-2] Else if numStatsGroup > 0, Deletion of individual stats group 
+ *   from list whose information are present in stats delete request.
+ *   [Step-3] Fill the result of the stats deletion in the SCH stats delete
+ *   response
+ * @params[in] 
+ *             Instance
+ *             Subscription delete req
+ *             Subscription delete rsp
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t deleteStatsInfo(Inst inst, SchStatsDeleteReq *statsDeleteReq, SchStatsDeleteRsp  *schStatsDeleteRsp)
+{
+   uint8_t statsGrpIdx=0;
+   CmLListCp  *statsGrpList =NULLP;
+
+   statsGrpList = &schCb[inst].statistics.statsGrpList;
+   
+   if(!statsDeleteReq->numStatsGroupToBeDeleted)
+   {
+      /* [Step-1] */
+      if(deleteFromStatsGrpList(inst,statsGrpList, statsDeleteReq->subscriptionId, 0, true) == ROK)
+      {
+         /* [Step 3]*/
+         schStatsDeleteRsp->subsDelRsp = RSP_OK;  
+         schStatsDeleteRsp->subsDelCause = SUCCESSFUL;
+      }
+      else
+      {
+         /* [Step-3]*/
+         schStatsDeleteRsp->subsDelRsp = RSP_NOK;  
+         schStatsDeleteRsp->subsDelCause = STATS_ID_NOT_FOUND; 
+      }
+   }
+   else
+   {
+      for(statsGrpIdx=0; statsGrpIdx<statsDeleteReq->numStatsGroupToBeDeleted; statsGrpIdx++)
+      {
+         /* [Step-2] */
+         if(deleteFromStatsGrpList(inst, statsGrpList, statsDeleteReq->subscriptionId,\
+                  statsDeleteReq->statsGrpIdToBeDelList[statsGrpIdx], false) == ROK)
+         {
+            /* [Step-3]*/
+            schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_OK;  
+            schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = SUCCESSFUL; 
+         }
+         else
+         {
+            /* [Step-3]*/
+            schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_NOK;  
+            schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = STATS_ID_NOT_FOUND; 
+         }
+      }
+      schStatsDeleteRsp->numStatsGroupDeleted = statsDeleteReq->numStatsGroupToBeDeleted;
+   }
+   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)
+{
+   Pst rspPst;
+   uint8_t ret =ROK;
+   SchStatsDeleteRsp  *schStatsDeleteRsp;
+   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;
+   }
+   
+   /* Process Stats delete request and fill stats delete response simultaneously */
+   SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
+   if(schStatsDeleteRsp == NULLP)
+   {
+      DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchProcStatsDeleteReq()");
+      return RFAILED;
+   }
+   schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
+   deleteStatsInfo(inst, statsDeleteReq, schStatsDeleteRsp);
+   
+   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 : SchProcStatsDeleteReq(): Failed to send Statistics Response");
+   }
+   SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
+
+   return ret;
+} /* End of SchProcStatsDeleteReq */
+
+/*******************************************************************
+ *
+ * @brief Fill and send statistics modification response to MAC
+ *
+ * @details
+ *
+ *    Function :  SchSendStatsRspToMac
+ *
+ *    Functionality: Fill and send statistics
+ * modification response to MAC
+ *
+ * @params[in]  Inst inst, SchMacRsp result
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchSendStatsModificationRspToMac(SchStatsModificationRsp *tmpSchStatsModRsp)
+{
+   Pst rspPst;
+   uint8_t ret = ROK;
+   SchStatsModificationRsp  *schStatsModificationRsp=NULLP;
+
+   DU_LOG("\nINFO   --> SCH : Filling statistics modification response");
+   SCH_ALLOC(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
+   if(schStatsModificationRsp == NULLP)
+   {
+      DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsModificationRspToMac()");
+      return RFAILED;
+   }
+
+   memcpy(schStatsModificationRsp, tmpSchStatsModRsp, sizeof(SchStatsModificationRsp));
+   memset(tmpSchStatsModRsp, 0, sizeof(SchStatsModificationRsp));
+
+   /* Filling response post */
+   memset(&rspPst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(rspPst, inst);
+   rspPst.event = EVENT_STATISTICS_MODIFY_RSP_TO_MAC;
+
+   ret = MacMessageRouter(&rspPst, (void *)schStatsModificationRsp);
+   if(ret == RFAILED)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchSendStatsModificationRspToMac(): Failed to send Statistics Modification Response");
+      return ret;
+   }
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Rejects all statistics modification group requested by MAC
+ *
+ * @details
+ *
+ *    Function : SchRejectAllStatsModification
+ *
+ *    Functionality: Add all statistics modification group received in statistics
+ *       request from MAC, to Reject-StatsModification-Group-List in statistics
+ *       response to MAC
+ *
+ * @params[in]  Statistics request from MAC
+ *              Cause of rejection
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchRejectAllStatsModification(SchStatsModificationReq *statsModificationReq, CauseOfResult cause)
+{
+   uint8_t grpIdx = 0;
+   SchStatsModificationRsp statsModificationRsp;
+
+   memset(&statsModificationRsp, 0, sizeof(SchStatsModificationRsp));
+
+   /* fill the subscriptionId and the rejected list in stats modification rsp */
+   statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
+   for(grpIdx = 0; grpIdx < statsModificationReq->numStatsGroup; grpIdx++)
+   {
+      statsModificationRsp.statsGrpRejectedList[grpIdx].groupId = statsModificationReq->statsGrpList[grpIdx].groupId;
+      statsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause;
+   }
+   statsModificationRsp.numGrpRejected = statsModificationReq->numStatsGroup;
+
+   return SchSendStatsModificationRspToMac(&statsModificationRsp);
+}
+
+/****************************************************************************************
+*
+* @brief Processes Statistics modification Request from MAC
+*
+* @details
+*
+*    Function :SchProcStatsModificationReq 
+*
+*    Functionality:
+*     This function process the statistics modification request from MAC:
+*     [Step -1] Check the stored stats group list empty.
+*        [Step - 1.1] If empty Send the rejected group list to MAC as a stats 
+*        modification response.
+*        [Step - 1.2] Else go to step 2.
+*     [Step -2] Traverse all stats group and validate each measurement types in
+*     each group.
+*     [Step -3] Check for any failure and if failed fill the remaining group's
+*     info in rejected list.
+*     [Step -4] Else Check if the received subscriptionId and groupId match the 
+*     values with the database node. 
+*        [Step -4.1] If  matches then follow the below mentioned steps.
+*           [Step -4.1.1] Stop the timer.
+*           [Step -4.1.2] Reconfigure stats group by adding a new entry for this
+*           statsGroup with updated configuration in database.
+*           [Step -4.1.3] if configured successfully, store stats info into
+*           stats mod rsp's accepted list, restart timer and go to step 4.1.4 
+*           [Step -4.1.4] Delete the old entry of this stats group..
+*        [Step -4.2] Else fill the group related info in stats modification rsp's 
+*           rejected list.
+*     [Step -5] Send the stats modification rsp to MAC
+* @params[in] Post structure
+*             Statistics modification Request from MAC
+* @return ROK     - success
+*         RFAILED - failure
+*
+* *******************************************************************************************/
+uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq)
+{
+   Inst inst;
+   uint8_t reqGrpIdx=0;
+   uint64_t subscriptionId =0;
+   bool allocFailed = false;
+   bool statsGrpFound= false;
+   CmLList *grpNode = NULLP;
+   SchStatsGrp *statsGrpInfo=NULLP;
+   SchStatsGrpInfo statsGrpToModify;
+   SchStatsModificationRsp statsModificationRsp;
+
+   inst=pst->dstInst - SCH_INST_START;
+
+   DU_LOG("\nINFO   -->  SCH : Received Statistics modification request from MAC");
+
+   if(statsModificationReq == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsModificationReq(): Received Null pointer");
+      return RFAILED;
+   }
+   memset(&statsModificationRsp, 0, sizeof(SchStatsRsp));
+
+   /* [Step -1] */
+   if(schCb[inst].statistics.statsGrpList.count)
+   {
+      /* [Step -1.2] */
+      subscriptionId = statsModificationReq->subscriptionId;
+
+      /* [Step - 2] */
+      for(reqGrpIdx=0; reqGrpIdx<statsModificationReq->numStatsGroup; reqGrpIdx++)
+      {
+         /* [Step - 3] */
+         statsGrpToModify = statsModificationReq->statsGrpList[reqGrpIdx];
+         if(allocFailed  != true)
+         {
+            CM_LLIST_FIRST_NODE(&schCb[inst].statistics.statsGrpList, grpNode);
+            while(grpNode)
+            {
+               /* [Step - 4] */
+               statsGrpInfo = (SchStatsGrp*)grpNode->node;
+               if((statsGrpInfo->subscriptionId== subscriptionId) && (statsGrpInfo->groupId== statsGrpToModify.groupId))
+               {
+                  statsGrpFound= true;
+                  break; 
+               }
+               grpNode = grpNode->next;
+            }
+
+            /* [Step - 4.1] */
+            if(statsGrpFound== true)
+            {
+               /* [Step - 4.1.1] */
+               if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
+               {
+                  schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
+               }
+
+               /* [Step - 4.1.2] */
+               if(schAddToStatsGrpList(inst, &statsModificationRsp, subscriptionId, &statsGrpToModify) != ROK)
+               {
+                  DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Failed to fill the stats group list");
+                  if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].groupId == statsGrpToModify.groupId)
+                  {
+                     /* [Step - 4.1.3] */
+                     schStartTmr(&schCb[inst], (PTR)(statsGrpInfo), EVENT_STATISTICS_TMR, statsGrpInfo->periodicity);
+                     if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)
+                     {
+                        allocFailed = true;
+                        break;
+                     }
+                  }
+               }
+               else
+               {
+                  /* [Step - 4.1.4] */
+                  deleteStatsGrpNode(inst, grpNode);
+               }
+            }
+            else
+            {
+               /* [Step - 4.2] */
+               statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
+               statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = STATS_ID_NOT_FOUND;
+               statsModificationRsp.numGrpRejected++;
+            }
+         }
+         else
+         {
+            statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
+            statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
+            statsModificationRsp.numGrpRejected++;
+         }
+      }
+
+      statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
+      SchSendStatsModificationRspToMac(&statsModificationRsp);
+   }
+   else
+   {
+      /* [Step -1.1] */
+      SchRejectAllStatsModification(statsModificationReq, STATS_ID_NOT_FOUND);
+   }
+   SCH_FREE(statsModificationReq, sizeof(SchStatsModificationReq));
+   return ROK;
+}
 /**********************************************************************
   End of file
  **********************************************************************/