[Epic-ID: ODUHIGH-538][Issue-ID: ODUHIGH-563] Fixes to read SCTP and EGTP configurati...
[o-du/l2.git] / src / 5gnrsch / sch.c
index 563cb5a..8279bf6 100644 (file)
@@ -131,6 +131,11 @@ uint8_t SchInstCfg(RgCfg *cfg, Inst  dInst)
       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");
@@ -590,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;
@@ -650,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 */
@@ -660,21 +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 */
-   pdsch = &pdcch->dci.pdschCfg; 
+   pdsch = &pdcch->dci[0].pdschCfg; 
 
    /* fill the PDSCH PDU */
    uint8_t cwCount = 0;
@@ -777,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);
@@ -924,13 +928,13 @@ 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*));
       }
    }
 
@@ -1293,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)
       {
@@ -1302,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 */
@@ -1383,7 +1387,7 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
    }
    
    /* Update statistics of PRB usage if stats calculation is enabled */
-   if(schCb[cell->instIdx].statistics.dlTotalPrbUsage)
+   if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
       prbAlloc->numPrbAlloc += numPrb;
 
    /* Update the remaining number for free PRBs */
@@ -1520,7 +1524,7 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
    }
 
    /* Update statistics of PRB usage if stats calculation is enabled */
-   if(schCb[cell->instIdx].statistics.ulTotalPrbUsage)
+   if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
       prbAlloc->numPrbAlloc += numPrb;
 
    /* Update the remaining number for free PRBs */
@@ -1579,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)
       {
@@ -1588,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
       {
@@ -1761,10 +1765,10 @@ uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb,
       /* Here comparing the slice cfg request with the slice stored in cellCfg */
       for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
       {
-         for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
+         for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
          {
             /* 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)))
+            if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai)))
             {
                if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
                {
@@ -2503,148 +2507,1070 @@ uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
 
 /*******************************************************************
  *
- * @brief Processes Statistics Request from MAC
+ * @brief Fill and send statistics response to MAC
  *
  * @details
  *
- *    Function : SchProcStatsReq
+ *    Function :  SchSendStatsRspToMac
  *
- *    Functionality:
- *       Processes Statistics Request from MAC
+ *    Functionality: Fill and send statistics response to MAC
  *
- * @params[in] 
+ * @params[in]  Inst inst, SchMacRsp result
  * @return ROK     - success
  *         RFAILED - failure
  *
  * ****************************************************************/
-uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
+uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
 {
-   uint8_t idx;
-   Inst    inst = pst->dstInst - SCH_INST_START;
-   SchMacRsp     rsp = RSP_OK;
-   CauseOfResult cause = SUCCESSFUL;
-   bool isDlTotlPrbUseCfgd = false, isUlTotlPrbUseCfgd = false;
+   Pst rspPst;
+   uint8_t ret = ROK;
+   SchStatsRsp  *schStatsRsp;
 
-   DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
+   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));
 
-   for(idx=0; idx < statsReq->numStats; idx++)
+   /* 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)
    {
-      switch(statsReq->statsList[idx].type)
-      {
-         case SCH_DL_TOTAL_PRB_USAGE:
-            {
-               /* Check if duplicate configuration */
-               if(schCb[inst].statistics.dlTotalPrbUsage)
-               {
-                  DU_LOG("\nERROR   -->  SCH : SCH_DL_TOTAL_PRB_USAGE stats already configured");
-                  rsp = RSP_NOK;
-                  cause = DUPLICATE_ENTRY;
-               }
+      DU_LOG("\nERROR  -->  SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
+      return ret;
+   }
+   return ret;
+}
 
-               /* Allocate memory */
-               SCH_ALLOC(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage));
-               if(!schCb[inst].statistics.dlTotalPrbUsage)
-               {
-                  DU_LOG("\nERROR   -->  SCH : Memory allocation failed for dlTotalPrbUsage in \
-                        SchProcStatsReq()");
-                  rsp = RSP_NOK;
-                  cause = RESOURCE_UNAVAILABLE;
-                  break;
-               }
+/*******************************************************************
+ *
+ * @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;
 
-               /* Initialize */
-               memset(schCb[inst].statistics.dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+   memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
 
-               /* Configure */
-               schCb[inst].statistics.dlTotalPrbUsage->schInst = inst;
-               schCb[inst].statistics.dlTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity;
-               cmInitTimers(&(schCb[inst].statistics.dlTotalPrbUsage->periodTimer), 1);
+   /* 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;
 
-               /* Start timer */
-               schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), \
-                     EVENT_DL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.dlTotalPrbUsage->periodicity);
+   return SchSendStatsRspToMac(&schStatsRsp);
+}
 
-               isDlTotlPrbUseCfgd = true;
-               break;
-            }
+/*******************************************************************
+ *
+ * @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;
 
-         case SCH_UL_TOTAL_PRB_USAGE:
-            {
-               /* Check if duplicate configuration */
-               if(schCb[inst].statistics.ulTotalPrbUsage)
+   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:
                {
-                  DU_LOG("\nERROR   -->  SCH : SCH_UL_TOTAL_PRB_USAGE stats already configured");
-                  rsp = RSP_NOK;
-                  cause = DUPLICATE_ENTRY;
+                  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;
                }
 
-               /* Allocate memory */
-               SCH_ALLOC(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage));
-               if(!schCb[inst].statistics.ulTotalPrbUsage)
+            case SCH_UL_TOTAL_PRB_USAGE:
                {
-                  DU_LOG("\nERROR   -->  SCH : Memory allocation failed for ulTotalPrbUsage in \
-                        SchProcStatsReq()");
-                  rsp = RSP_NOK;
-                  cause = RESOURCE_UNAVAILABLE;
+                  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;
                }
 
-               /* Initialize */
-               memset(schCb[inst].statistics.ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
-
-               /* Configure */
-               schCb[inst].statistics.ulTotalPrbUsage->schInst = inst;
-               schCb[inst].statistics.ulTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity;
-               cmInitTimers(&(schCb[inst].statistics.ulTotalPrbUsage->periodTimer), 1);
+            default:
+               {
+                  DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Invalid measurement type [%d]", \
+                        grpInfo->statsList[reqMeasIdx]);
+                  measTypeInvalid = true;
+                  cause = PARAM_INVALID;
+                  break;
+               }
+         }
 
-               /* Start timer */
-               schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), \
-                     EVENT_UL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.ulTotalPrbUsage->periodicity);
+         if(measTypeInvalid)
+         {
+            ret =RFAILED;
+            break;
+         }
+      }
 
-               isUlTotlPrbUseCfgd = true;
+      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;
             }
-         default:
+         }
+
+         if(grpInfoDb->kpiStats.ulTotalPrbUsage)
+         {
+            /* Step 2.2 */
+            if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK)
             {
-               DU_LOG("\nERROR   -->  SCH : Invalid statistics type [%d]", statsReq->statsList[idx].type);
-               rsp = RSP_NOK;
-               cause = PARAM_INVALID;
+               DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
+               cause = RESOURCE_UNAVAILABLE;
+               ret =RFAILED;
+               break;
             }
-      } /* End of switch */
+         }
+
+         /* 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);
 
-      if(rsp == RSP_NOK)
+         /* 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
       {
-         /* If failed to configure any KPI, then clear configuration of other
-          * KPIs that were configured successfully as part of this statsReq */
-         if(isDlTotlPrbUseCfgd)
+         /*Step -4 */
+         if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
          {
-            if((schChkTmr((PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR)) == FALSE)
-            {
-               schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR);
+            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;
             }
-            SCH_FREE(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage));
          }
+      }
+   }
+
+   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;
+   }
 
-         if(isUlTotlPrbUseCfgd)
+}
+
+/*******************************************************************
+ *
+ * @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
          {
-            if((schChkTmr((PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR)) == FALSE)
+            /* [Step 4] */
+            if(statsGrpInfo->groupId== groupId) 
             {
-               schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR);
+               cmLListDelFrm(statsGrpList, grpNode);
+               deleteStatsGrpNode(inst, grpNode);
+               statsFound = true;
             }
-            SCH_FREE(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage));
          }
-         break;
       }
-   } /* End of FOR */
+      CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
+   }
 
-   SCH_FREE(statsReq, sizeof(SchStatsReq));
+   /* [Step 5] */
+   if(deleteAllGrp == true)
+   {
+      return ROK;
+   }
+   else
+   {
+      if(statsFound == true)
+         return ROK;
+   }
+   return RFAILED;
+}
 
-   /* TODO : in next gerrit */
-   //SchSendStatsRspToMac(inst, rsp, cause);
+/*******************************************************************
+ *
+ * @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;
-} /* End of SchProcStatsReq */
+}
 
+/*******************************************************************
+ *
+ * @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
  **********************************************************************/