[Epic-ID: ODUHIGH-516][Task-ID: ODUHIGH-530] Implementation of Stats Modification... 20/12120/9
authorpborla <pborla@radisys.com>
Sun, 26 Nov 2023 17:51:27 +0000 (23:21 +0530)
committerpborla <pborla@radisys.com>
Wed, 29 Nov 2023 14:27:48 +0000 (19:57 +0530)
Change-Id: I3de463b0aba3480b8432b1b1e6f06bdf1f57830d
Signed-off-by: pborla <pborla@radisys.com>
14 files changed:
src/5gnrmac/mac.h
src/5gnrmac/mac_cfg_hdl.c
src/5gnrmac/mac_msg_router.c
src/5gnrsch/sch.c
src/5gnrsch/sch.h
src/5gnrsch/sch_msg_router.c
src/5gnrsch/sch_slot_ind.c
src/cm/du_app_mac_inf.c
src/cm/du_app_mac_inf.h
src/cm/mac_sch_interface.h
src/du_app/du_e2ap_mgr.c
src/du_app/du_e2ap_mgr.h
src/du_app/du_mgr_msg_router.c
src/du_app/du_msg_hdl.c

index 5a1db5a..46b8a54 100644 (file)
@@ -303,6 +303,7 @@ uint8_t MacProcSchCellDeleteRsp(Pst *pst, SchCellDeleteRsp *schCellDeleteRsp);
 uint8_t MacProcSchStatsRsp(Pst *pst, SchStatsRsp *schStatsRsp);
 uint8_t MacProcSchStatsInd(Pst *pst, SchStatsInd *schStatsInd);
 uint8_t MacProcSchStatsDeleteRsp(Pst *pst, SchStatsDeleteRsp *schStatsDeleteRsp);
+uint8_t MacProcSchStatsModificationRsp(Pst *pst, SchStatsModificationRsp *schStatsModificationRsp);
 
 #endif
 /**********************************************************************
index c682a66..3957ac2 100644 (file)
@@ -77,6 +77,13 @@ MacDuStatsDeleteRspFunc macDuStatsDeleteRspOpts[] =
    packDuMacStatsDeleteRsp   /* packing for light weight loosly coupled */
 };
 
+MacDuStatsModificationRspFunc macDuStatsModificationRspOpts[] =
+{
+   packDuMacStatsModificationRsp,   /* packing for loosely coupled */
+   DuProcMacStatsModificationRsp,   /* packing for tightly coupled */
+   packDuMacStatsModificationRsp   /* packing for light weight loosly coupled */
+};
+
 /**
  * @brief Layer Manager  Configuration request handler for Scheduler
  *
@@ -1524,6 +1531,301 @@ uint8_t MacProcStatsDeleteReq(Pst *pst, MacStatsDeleteReq *macStatsDeleteReq)
    return ret;
 }
 
+/**
+ * @brief Fill and send statistics modification response to DU APP
+ *
+ * @details
+ *
+ *     Function : MacSendStatsModificationRspToDuApp 
+ *
+ *     Fill and send statistics modification response to DU APP
+ *
+ *  @param[in]  Stats modification Response
+ *  @return  int
+ *      -# ROK
+ **/
+uint8_t MacSendStatsModificationRspToDuApp(MacStatsModificationRsp *tmpMacStatsModRsp)
+{
+   Pst  pst;
+   uint8_t ret = ROK;
+   MacStatsModificationRsp *macStatsModificationRsp = NULLP;
+
+   DU_LOG("\nINFO  -->  MAC : MacSendStatsModificationRspToDuApp: Sending Statistics Modification Response to DU APP");
+
+
+   MAC_ALLOC_SHRABL_BUF(macStatsModificationRsp, sizeof(MacStatsModificationRsp));
+   if(macStatsModificationRsp == NULLP)
+   {
+      DU_LOG("\nERROR  -->  MAC : Failed to allocate memory in MacProcSchStatsModificationRsp");
+      ret = RFAILED;
+   }
+   else
+   {
+      memcpy(macStatsModificationRsp, tmpMacStatsModRsp, sizeof(MacStatsModificationRsp));
+      memset(tmpMacStatsModRsp, 0, sizeof(MacStatsModificationRsp));
+
+      memset(&pst, 0, sizeof(Pst));
+      FILL_PST_MAC_TO_DUAPP(pst, EVENT_MAC_STATISTICS_MODIFY_RSP);
+      if(((*macDuStatsModificationRspOpts[pst.selector])(&pst, macStatsModificationRsp))!= ROK)
+      {
+         DU_LOG("\nERROR  -->  MAC : Failed to send statistics modification response to DU APP");
+         MAC_FREE_SHRABL_BUF(MAC_MEM_REGION, MAC_POOL, macStatsModificationRsp, sizeof(MacStatsModificationRsp));
+         ret = RFAILED;
+      }
+   }
+
+   return ret;
+}
+
+/**
+ * @brief Mac process the statistics modification rsp received from sch.
+ *
+ * @details
+ *
+ *     Function : MacProcSchStatsModificationRsp
+ *
+ *     This function  process the statistics modification response received from sch
+ *     [Step -1] Fetch pointer to statistics response from pending list saved at
+ *     MAC during processing statistics request from DU APP
+ *     [Step -2] Fill the list of accepted list
+ *     [Step -3] Fill the list of rejected list
+ *     [Step -4] Send statistics modification response to DU APP
+ *
+ *  @param[in]  Pst           *pst
+ *  @param[in]  SchStatsModificationRsp *schStatsModificationRsp
+ *  @return  int
+ *      -# ROK
+ **/
+uint8_t MacProcSchStatsModificationRsp(Pst *pst, SchStatsModificationRsp *schStatsModificationRsp)
+{
+   uint8_t ret = RFAILED;
+   uint8_t idx = 0, accptdIdx = 0, rjctdIdx = 0;
+   MacStatsModificationRsp *macStatsModificationRsp = NULLP;
+
+   if(schStatsModificationRsp)
+   {
+      /* [Step -1] */
+      for(idx = 0; idx < macCb.statistics.numPendingStatsRsp; idx++)
+      {
+         if(macCb.statistics.pendingStatsRsp[idx].subscriptionId == schStatsModificationRsp->subscriptionId)
+         {
+            macStatsModificationRsp = &macCb.statistics.pendingStatsRsp[idx];
+            break;
+         }
+      }
+
+      if(macStatsModificationRsp == NULLP)
+      {
+         MAC_FREE(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
+         return RFAILED;
+      }
+      
+      /* [Step -2] */
+      for(accptdIdx = 0; accptdIdx<schStatsModificationRsp->numGrpAccepted && macStatsModificationRsp->numGrpAccepted<MAX_NUM_STATS_GRP; accptdIdx++)
+      {
+         macStatsModificationRsp->statsGrpAcceptedList[macStatsModificationRsp->numGrpAccepted++] = schStatsModificationRsp->statsGrpAcceptedList[accptdIdx];
+      }
+
+      /* [Step -3] */
+      for(rjctdIdx = 0; rjctdIdx < schStatsModificationRsp->numGrpRejected && macStatsModificationRsp->numGrpRejected<MAX_NUM_STATS_GRP; rjctdIdx++)
+      {
+         macStatsModificationRsp->statsGrpRejectedList[macStatsModificationRsp->numGrpRejected].groupId = \
+            schStatsModificationRsp->statsGrpRejectedList[rjctdIdx].groupId;
+         macStatsModificationRsp->statsGrpRejectedList[macStatsModificationRsp->numGrpRejected].cause = \
+            schStatsModificationRsp->statsGrpRejectedList[rjctdIdx].cause;
+         macStatsModificationRsp->numGrpRejected++;
+      }
+
+      /* [Step -4] */
+      ret = MacSendStatsModificationRspToDuApp(macStatsModificationRsp);
+   }
+   MAC_FREE(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Rejects all statistics modification group requested by DU APP
+ *
+ * @details
+ *
+ *    Function : MacRejectAllStatsModification
+ *
+ *    Functionality: Add all statistics modification group received in statistics
+ *       request from DU APP, to Reject-StatsModification-Group-List in statistics
+ *       response to DU APP
+ *
+ * @params[in]  Statistics request from DU APP
+ *              Cause of rejection
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t MacRejectAllStatsModification(MacStatsModificationReq *macStatsModificationReq, CauseOfResult cause)
+{
+   uint8_t grpIdx = 0;
+   MacStatsModificationRsp macStatsModificationRsp;
+
+   memset(&macStatsModificationRsp, 0, sizeof(MacStatsModificationRsp));
+
+   /* fill the subscriptionId and the rejected list in stats modification rsp */
+   macStatsModificationRsp.subscriptionId = macStatsModificationReq->subscriptionId;
+   for(grpIdx = 0; grpIdx < macStatsModificationReq->numStatsGroup; grpIdx++)
+   {
+      macStatsModificationRsp.statsGrpRejectedList[grpIdx].groupId = macStatsModificationReq->statsGrpList[grpIdx].groupId;
+      macStatsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause;
+   }
+   macStatsModificationRsp.numGrpRejected = macStatsModificationReq->numStatsGroup;
+
+   return MacSendStatsModificationRspToDuApp(&macStatsModificationRsp);
+}
+
+/**
+ * @brief Mac process the statistics Modification Req received from DUAPP
+ *
+ * @details
+ *
+ *     Function : MacProcStatsModificationReq
+ *
+ *     This function process the statistics Modification request from duapp:
+ *     [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
+ *     mac-stats-response message.
+ *     [Step 4] Even if one group passes all validation, it is sent to SCH in
+ *     statistics request. The mac-stats-response message is added to
+ *     pending-response list. This will be sent to DU APP after stats response
+ *     is received from SCH.
+ *     [Step 5] If none of the groups passes all validation, mac-stats-response
+ *     is sent to du app with all group as part of stats-group-rejected-list.
+ *
+ *  @param[in]  Pst      *pst
+ *  @param[in]  StatsModificationReq *statsModificationReq
+ *  @return  int
+ *      -# ROK
+ **/
+uint8_t MacProcStatsModificationReq(Pst *pst, MacStatsModificationReq *macStatsModificationReq)
+{
+   Pst           schPst;
+   uint8_t       ret = RFAILED;
+   bool          measTypeInvalid = false;
+   uint8_t       macStatsGrpIdx = 0, macStatsIdx = 0;
+   uint8_t       schStatsGrpIdx = 0, schStatsIdx = 0;
+   MacStatsGrpInfo          *macStatsGrp = NULLP;
+   SchStatsModificationReq  *schStatsModificationReq = NULLP;
+   MacStatsModificationRsp  *macStatsModificationRsp = NULLP;
+
+   DU_LOG("\nINFO   -->  MAC : Received Statistics Modification Request from DU_APP");
+
+   if(macStatsModificationReq == NULLP)
+   {
+      DU_LOG("\nERROR  -->  MAC : MacProcStatsModificationReq(): Received Null pointer");
+      return RFAILED;
+   }
+
+   /* [Step -1] */
+   if(macCb.statistics.numPendingStatsRsp >= MAX_PENDING_STATS_RSP)
+   {
+      DU_LOG("\nERROR  -->  MAC : MacProcStatsModificationReq: Maximum number of statistics response is pending. \
+         Cannot process new request.");
+      MacRejectAllStatsModification(macStatsModificationReq, RESOURCE_UNAVAILABLE);
+      MAC_FREE_SHRABL_BUF(pst->region, pst->pool, macStatsModificationReq, sizeof(MacStatsModificationReq));
+      return RFAILED;
+   }
+
+   MAC_ALLOC(schStatsModificationReq, sizeof(SchStatsModificationReq));
+   if(schStatsModificationReq == NULLP)
+   {
+      DU_LOG("\nERROR  -->  MAC : MacProcStatsModificationReq: Failed to allocate memory");
+      MacRejectAllStatsModification(macStatsModificationReq, RESOURCE_UNAVAILABLE);
+      MAC_FREE_SHRABL_BUF(pst->region, pst->pool, macStatsModificationReq, sizeof(MacStatsModificationReq));
+      return RFAILED;
+   }
+
+   macStatsModificationRsp = &macCb.statistics.pendingStatsRsp[macCb.statistics.numPendingStatsRsp];
+   memset(macStatsModificationRsp, 0, sizeof(MacStatsModificationRsp));
+
+   /* [Step 2]  */
+   schStatsModificationReq->subscriptionId = macStatsModificationReq->subscriptionId;
+   schStatsModificationReq->numStatsGroup = 0;
+   for(macStatsGrpIdx = 0; macStatsGrpIdx < macStatsModificationReq->numStatsGroup; macStatsGrpIdx++)
+   {
+      measTypeInvalid = false;
+      schStatsIdx = 0;
+      macStatsGrp = &macStatsModificationReq->statsGrpList[macStatsGrpIdx];
+
+      for(macStatsIdx=0; macStatsIdx < macStatsGrp->numStats; macStatsIdx++)
+      {
+         switch(macStatsGrp->statsList[macStatsIdx])
+         {
+            case MAC_DL_TOTAL_PRB_USAGE:
+               {
+                  schStatsModificationReq->statsGrpList[schStatsGrpIdx].statsList[schStatsIdx] = SCH_DL_TOTAL_PRB_USAGE;
+                  break;
+               }
+            case MAC_UL_TOTAL_PRB_USAGE:
+               {
+                  schStatsModificationReq->statsGrpList[schStatsGrpIdx].statsList[schStatsIdx] = SCH_UL_TOTAL_PRB_USAGE;
+                  break;
+               }
+            default:
+               {
+                  DU_LOG("\nERROR  -->  MAC : MacProcStatsModificationReq: Invalid measurement type [%d]", \
+                     macStatsGrp->statsList[macStatsIdx]);
+                  measTypeInvalid = true;
+               }
+         }
+
+         if(measTypeInvalid)
+         {
+            memset(&schStatsModificationReq->statsGrpList[schStatsGrpIdx], 0, sizeof(SchStatsGrpInfo));
+            break;
+         }
+
+         schStatsIdx++;
+      }
+
+      if(!measTypeInvalid)
+      {
+         schStatsModificationReq->statsGrpList[schStatsGrpIdx].groupId = macStatsGrp->groupId;
+         schStatsModificationReq->statsGrpList[schStatsGrpIdx].periodicity = macStatsGrp->periodicity;
+         schStatsModificationReq->statsGrpList[schStatsGrpIdx].numStats = schStatsIdx;
+         schStatsGrpIdx++;
+      }
+      else
+      {
+         /* [Step 3] */
+         macStatsModificationRsp->statsGrpRejectedList[macStatsModificationRsp->numGrpRejected].groupId = macStatsGrp->groupId;
+         macStatsModificationRsp->statsGrpRejectedList[macStatsModificationRsp->numGrpRejected].cause = PARAM_INVALID;
+         macStatsModificationRsp->numGrpRejected++;
+      }
+   }
+   schStatsModificationReq->numStatsGroup = schStatsGrpIdx;
+
+   macStatsModificationRsp->subscriptionId = macStatsModificationReq->subscriptionId;
+   if(schStatsModificationReq->numStatsGroup)
+   {
+      /* [Step 4] */
+      macCb.statistics.numPendingStatsRsp++;
+
+      FILL_PST_MAC_TO_SCH(schPst, EVENT_STATISTICS_MODIFY_REQ_TO_SCH);
+      ret = SchMessageRouter(&schPst, (void *)schStatsModificationReq);
+   }
+   else
+   {
+      /* [Step 5] */
+      DU_LOG("\nERROR  -->  MAC : MacProcStatsModificationReq: All statistics group found invalid");
+      MAC_FREE(schStatsModificationReq, sizeof(SchStatsModificationReq));
+      ret = MacSendStatsModificationRspToDuApp(macStatsModificationRsp);
+   }
+
+   MAC_FREE_SHRABL_BUF(pst->region, pst->pool, macStatsModificationReq, sizeof(MacStatsModificationReq));
+   return ret;
+}
+
 /**********************************************************************
   End of file
  **********************************************************************/
index 88c0689..59d45be 100755 (executable)
@@ -200,6 +200,12 @@ void MacHdlDuappEvents(Pst *pst, Buffer *mBuf)
             unpackMacStatsDeleteReq(MacProcStatsDeleteReq, pst, mBuf);
             break;
          }
+      case EVENT_MAC_STATISTICS_MODIFY_REQ:
+         {
+            /* Process Statistics modification Request */
+            unpackMacStatsModificationReq(MacProcStatsModificationReq, pst, mBuf);
+            break;
+         }
 
 
       default:
@@ -358,6 +364,9 @@ void callFlowMacActvTsk(Pst *pst)
                case EVENT_MAC_STATS_DELETE_REQ:
                   strcpy(message,"EVENT_MAC_STATS_DELETE_REQ");
                   break;
+               case EVENT_MAC_STATISTICS_MODIFY_REQ:
+                  strcpy(message,"EVENT_MAC_STATISTICS_MODIFY_REQ");
+                  break;
                default:
                   strcpy(message,"Invalid Event");
                   break;
@@ -502,6 +511,11 @@ void callFlowMacActvTsk(Pst *pst)
                         strcpy(message,"EVENT_STATISTICS_DELETE_RSP_TO_MAC");
                         break;
                      }
+                  case EVENT_STATISTICS_MODIFY_RSP_TO_MAC:
+                     {
+                        strcpy(message,"EVENT_STATISTICS_MODIFY_RSP_TO_MAC");
+                        break;
+                     }
                   default:
                      strcpy(message,"Invalid Event");
                      break;
@@ -661,6 +675,11 @@ uint8_t MacMessageRouter(Pst *pst, void *msg)
             MacProcSchStatsDeleteRsp(pst, (SchStatsDeleteRsp *)msg);
             break;
          }
+      case EVENT_STATISTICS_MODIFY_RSP_TO_MAC:
+         {
+            MacProcSchStatsModificationRsp(pst, (SchStatsModificationRsp *)msg);
+            break;
+         }
       default:
          {
             return RFAILED;
index d8adc88..d3fbcec 100644 (file)
@@ -2606,39 +2606,206 @@ uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
  *       Instead, we can traverse through KPI-Active-List and update
  *       all entries in this list.
  *
- * @params[in]  Statistics request from MAC
- *              Cause of rejection
+ * @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(Inst inst, SchStatsGrp *grpInfo)
+uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo)
 {
    CmLList  *node = NULLP;
 
-   /* If DL Total PRB Usage configured for this stats group, add to list */
-   if(grpInfo->kpiStats.dlTotalPrbUsage)
+   SCH_ALLOC(node, sizeof(CmLList));
+   if(node)
    {
-      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++)
       {
-         node->node = (PTR)grpInfo->kpiStats.dlTotalPrbUsage; 
-         cmLListAdd2Tail(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, node);
+         /* 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 UL Total PRB Usage configured for this stats group, add to list */
-   node = NULLP;
-   if(grpInfo->kpiStats.ulTotalPrbUsage)
+   if(ret != ROK)
    {
-      SCH_ALLOC(node, sizeof(CmLList));
-      if(node)
+      /* Step 3 */
+      if(grpInfoDb)
       {
-         node->node = (PTR)grpInfo->kpiStats.ulTotalPrbUsage; 
-         cmLListAdd2Tail(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, node);
+         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;
 }
 
@@ -2661,8 +2828,7 @@ uint8_t schAddToKpiActiveList(Inst inst, SchStatsGrp *grpInfo)
  *     is not configured and it is added to stats-group-rejected-list in
  *     sch-stats-response message.
  *     [Step 4] If a group passes all validation, it is added to SCH database.
- *     A timer is started for this group. And the group is added to 
- *     stats-group-accepted-list in sch-stats-response message.
+ *     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.
  *
@@ -2674,14 +2840,11 @@ uint8_t schAddToKpiActiveList(Inst inst, SchStatsGrp *grpInfo)
  * ****************************************************************/
 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
 {
-   uint8_t grpIdx = 0, reqGrpIdx = 0, reqMeasIdx = 0;
-   Inst    inst = pst->dstInst - SCH_INST_START;
-   bool    measTypeInvalid;
-   CauseOfResult cause;
-   CmLList *statsGrpNode=NULLP; 
+   bool allocFailed = false;
+   uint8_t grpIdx = 0, reqGrpIdx = 0;
    SchStatsGrpInfo *grpInfo = NULLP;
-   SchStatsGrp *grpInfoDb = NULLP;
    SchStatsRsp schStatsRsp;
+   Inst inst = pst->dstInst - SCH_INST_START;
 
    DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
 
@@ -2691,9 +2854,7 @@ uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
       return RFAILED;
    }
 
-   /* [Step 1] Basic validation. If fails, all stats group in stats request are rejected */
-   
-   /* If maximum number of statistics already configured */
+   /*Step -1*/
    if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP)
    {
       DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Maximum number of statistics configured. \
@@ -2705,133 +2866,40 @@ uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
 
    memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
 
-   /* [Step 2] Traverse all stats group and validate each measurement types in each group */
+   /*Step -2*/
    for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
    {
-      measTypeInvalid = false;
       grpInfo = &statsReq->statsGrpList[reqGrpIdx];
-      SCH_ALLOC(grpInfoDb, sizeof(SchStatsGrp));
-      if(grpInfoDb == NULLP)
+      /*Step -3 */
+      if(allocFailed  == true)
       {
-
-         DU_LOG("\nERROR   -->  SCH : Memory allocation failed for dlTotalPrbUsage in \
-               SchProcStatsReq()");
-         measTypeInvalid = true;
-         cause = RESOURCE_UNAVAILABLE;
+         schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
+         schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
+         schStatsRsp.numGrpRejected++;
       }
       else
       {
-         for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
+         /*Step -4 */
+         if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
          {
-            switch(grpInfo->statsList[reqMeasIdx])
-            {
-               case SCH_DL_TOTAL_PRB_USAGE:
-                  {
-                     /* Allocate memory */
-                     SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
-                     if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
-                     {
-                        DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
-                        measTypeInvalid = true;
-                        cause = RESOURCE_UNAVAILABLE;
-                     }
-                     break;
-                  }
-
-               case SCH_UL_TOTAL_PRB_USAGE:
-                  {
-                     /* Allocate memory */
-                     SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
-                     if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
-                     {
-                        DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
-                        measTypeInvalid = true;
-                        cause = RESOURCE_UNAVAILABLE;
-                     }
-                     break;
-                  }
-
-               default:
-                  {
-                     DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Invalid measurement type [%d]", \
-                           grpInfo->statsList[reqMeasIdx]);
-                     measTypeInvalid = true;
-                     cause = PARAM_INVALID;
-                     break;
-                  }
-            }
-
-            /* [Step 3 a] If any measurement type validation fails in a group, that group
-             *  is not configured */
-            if(measTypeInvalid)
-            {
-               SCH_FREE(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
-               SCH_FREE(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
-               memset(grpInfoDb, 0, sizeof(SchStatsGrp));   
-               break;
+            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;
             }
          }
-      } 
-      /* [Step 4] If a group passes all validation, it is added to SCH database.
-       * A timer is started for this group. And the group is added to
-       * stats-group-accepted-list in sch-stats-response message. */
-      if(!measTypeInvalid)
-      {
-         /* Add this group's configured KPIs to list of Active KPIs */
-         if(schAddToKpiActiveList(inst, grpInfoDb) == ROK)
-         {
-            grpInfoDb->schInst = inst;
-            grpInfoDb->subscriptionId = statsReq->subscriptionId;
-            grpInfoDb->groupId = grpInfo->groupId;
-            grpInfoDb->periodicity = grpInfo->periodicity;
-
-
-            /* Start timer */
-            cmInitTimers(&(grpInfoDb->periodTimer), 1);
-            schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
-
-
-            /* Adding the information in link list*/
-            SCH_ALLOC(statsGrpNode, sizeof(CmLList));
-            if(statsGrpNode)
-            {
-               statsGrpNode->node = (PTR) grpInfoDb;
-               cmLListAdd2Tail(&schCb[inst].statistics.statsGrpList, statsGrpNode);
-               schStatsRsp.statsGrpAcceptedList[schStatsRsp.numGrpAccepted] = grpInfo->groupId;
-               schStatsRsp.numGrpAccepted++;
-               grpIdx++;
-            }
-            else
-            {
-               DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
-               SCH_FREE(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
-               SCH_FREE(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
-               SCH_FREE(grpInfoDb, sizeof(SchStatsGrp));
-               schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
-               schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = cause;
-               schStatsRsp.numGrpRejected++;
-            }
-         }
-      }
-      else
-      {
-         /* [Step 3 b] The rejected group is added to stats-group-rejected-list in
-          * sch-stats-response message */
-         schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
-         schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = cause;
-         schStatsRsp.numGrpRejected++;
       }
    }
-   schStatsRsp.subscriptionId = statsReq->subscriptionId;
 
+   schStatsRsp.subscriptionId = statsReq->subscriptionId;
    SCH_FREE(statsReq, sizeof(SchStatsReq));
-
-   /* [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
-    * and stats-group-accepted-list. */
+   
+   /*Step -5 */
    SchSendStatsRspToMac(&schStatsRsp);
 
    return ROK;
-} /* End of SchProcStatsReq */
+}
 
 /*******************************************************************
  *
@@ -2957,35 +3025,106 @@ uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
 
 /*******************************************************************
  *
- * @brief Delete statistics group
+ * @brief Delete node from active kpi list
  *
  * @details
  *
- *    Function : deleteStatsGrp
+ *    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 Node
- * @return ROK     - success
- *         RFAILED - failure
+ *           Stats Grp info
+ * @return void
  *
  * ****************************************************************/
-void deleteStatsGrp(Inst inst, CmLList *grpNode)
+void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo)
 {
-   SchStatsGrp *statsGrpInfo=NULLP;
-   
-   if(grpNode)
+   if(statsGrpInfo)
    {
-      statsGrpInfo = (SchStatsGrp*)grpNode->node;
-      SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
-      SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+      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));
@@ -3043,7 +3182,7 @@ uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t  sub
          {
             /* [Step 3] */
             cmLListDelFrm(statsGrpList, grpNode);
-            deleteStatsGrp(inst, grpNode);
+            deleteStatsGrpNode(inst, grpNode);
          }
          else
          {
@@ -3051,7 +3190,7 @@ uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t  sub
             if(statsGrpInfo->groupId== groupId) 
             {
                cmLListDelFrm(statsGrpList, grpNode);
-               deleteStatsGrp(inst, grpNode);
+               deleteStatsGrpNode(inst, grpNode);
                statsFound = true;
             }
          }
@@ -3207,6 +3346,232 @@ uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
    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
  **********************************************************************/
index 58e1c68..3d5e9f1 100644 (file)
@@ -818,6 +818,8 @@ uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq);
 uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd  *statsInd);
 uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo);
 uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq);
+uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq);
+void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo);
 /**********************************************************************
   End of file
  **********************************************************************/
index bad7cea..4cbd958 100755 (executable)
@@ -254,6 +254,11 @@ void callFlowSchMsgRouter(Pst *pst)
             strcpy(message,"EVENT_STATISTICS_DELETE_REQ_TO_SCH");
             break;
          }
+      case EVENT_STATISTICS_MODIFY_REQ_TO_SCH:
+         {
+            strcpy(message,"EVENT_STATISTICS_MODIFY_REQ_TO_SCH");
+            break;
+         }
       default:
          strcpy(message,"Invalid Event");
          break;
@@ -386,6 +391,11 @@ uint8_t SchMessageRouter(Pst *pst, void *msg)
          SchProcStatsDeleteReq(pst, (SchStatsDeleteReq *)msg);
          break;
       }
+      case EVENT_STATISTICS_MODIFY_REQ_TO_SCH:
+      {
+         SchProcStatsModificationReq(pst, (SchStatsModificationReq *)msg);
+         break;
+      }
       default:
       {
          DU_LOG("\nERROR  -->  SCH : SchMessageRouter(): Invalid event [%d] received", pst->event);
index 2a21774..534100d 100644 (file)
@@ -757,8 +757,11 @@ uint8_t SchProcSlotInd(Pst *pst, SlotTimingInfo *slotInd)
    while(node)
    {
       dlTotalPrbUsage = (TotalPrbUsage *)node->node;
-      dlTotalPrbUsage->numPrbUsedForTx += cell->schDlSlotInfo[slot]->prbAlloc.numPrbAlloc;
-      dlTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
+      if(dlTotalPrbUsage)
+      {
+         dlTotalPrbUsage->numPrbUsedForTx += cell->schDlSlotInfo[slot]->prbAlloc.numPrbAlloc;
+         dlTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
+      }
       node = node->next;
    }
    
index 4886061..b05b988 100644 (file)
@@ -2713,6 +2713,164 @@ uint8_t unpackDuMacStatsDeleteRsp(MacDuStatsDeleteRspFunc func, Pst *pst, Buffer
     return RFAILED;
 }
 
+/*******************************************************************
+*
+* @brief Packs and Sends Statistics Modification Request from DUAPP to MAC
+*
+* @details
+*
+*    Function : packDuMacStatsModificationReq
+*
+*    Functionality:
+*       Packs and Sends statistics Modification request from DUAPP to MAC
+*
+*
+* @params[in] Post structure pointer
+*             StatsModificationReq pointer
+* @return ROK     - success
+*         RFAILED - failure
+*
+* ****************************************************************/
+uint8_t packDuMacStatsModificationReq(Pst *pst, MacStatsModificationReq *statsModificationReq)
+{
+    Buffer *mBuf = NULLP;
+
+    if(pst->selector == ODU_SELECTOR_LWLC)
+    {
+       if (ODU_GET_MSG_BUF(pst->region, pst->pool, &mBuf) != ROK)
+       {
+          DU_LOG("\nERROR  --> MAC : Memory allocation failed at packDuMacStatsModificationReq");
+          return RFAILED;
+       }
+       /* pack the address of the structure */
+       CMCHKPK(oduPackPointer,(PTR)statsModificationReq, mBuf);
+    }
+    else
+    {
+       DU_LOG("\nERROR  -->  MAC: Only LWLC supported for packDuMacStatsModificationReq");
+       return RFAILED;
+    }
+    return ODU_POST_TASK(pst,mBuf);
+}
+
+/*******************************************************************
+*
+* @brief Unpacks Statistics Modification Request received from DU APP
+*
+* @details
+*
+*    Function : unpackMacStatsModificationReq
+*
+*    Functionality:
+*         Unpacks Statistics Modification Request received from DU APP
+*
+* @params[in] Pointer to Handler
+*             Post structure pointer
+*             Message Buffer
+* @return ROK     - success
+*         RFAILED - failure
+*
+* ****************************************************************/
+uint8_t unpackMacStatsModificationReq(DuMacStatsModificationReqFunc func, Pst *pst, Buffer *mBuf)
+{
+    if(pst->selector == ODU_SELECTOR_LWLC)
+    {
+       MacStatsModificationReq *statsModificationReq=NULLP;
+
+       /* unpack the address of the structure */
+       CMCHKUNPK(oduUnpackPointer, (PTR *)&statsModificationReq, mBuf);
+       ODU_PUT_MSG_BUF(mBuf);
+       return (*func)(pst, statsModificationReq);
+    }
+    else
+    {
+       /* Nothing to do for other selectors */
+       DU_LOG("\nERROR  -->  DU APP : Only LWLC supported for Statistics Modification Request ");
+       ODU_PUT_MSG_BUF(mBuf);
+    }
+
+    return RFAILED;
+}
+
+/*******************************************************************
+*
+* @brief Packs and Sends Statistics Modification Response from MAC to DUAPP
+*
+* @details
+*
+*    Function : packDuMacStatsModificationRsp
+*
+*    Functionality:
+*       Packs and Sends statistics Modification response from MAC to DUAPP
+*
+*
+* @params[in] Post structure pointer
+*             StatsModificationRsp pointer
+* @return ROK     - success
+*         RFAILED - failure
+*
+* ****************************************************************/
+uint8_t packDuMacStatsModificationRsp(Pst *pst, MacStatsModificationRsp *statsModificationRsp)
+{
+    Buffer *mBuf = NULLP;
+
+    if(pst->selector == ODU_SELECTOR_LWLC)
+    {
+       if (ODU_GET_MSG_BUF(pst->region, pst->pool, &mBuf) != ROK)
+       {
+          DU_LOG("\nERROR  --> MAC : Memory allocation failed at packDuMacStatsModificationRsp");
+          return RFAILED;
+       }
+       /* pack the address of the structure */
+       CMCHKPK(oduPackPointer,(PTR)statsModificationRsp, mBuf);
+    }
+    else
+    {
+       DU_LOG("\nERROR  -->  MAC: Only LWLC supported for packDuMacStatsModificationRsp");
+       return RFAILED;
+    }
+    return ODU_POST_TASK(pst,mBuf);
+}
+
+/*******************************************************************
+*
+* @brief Unpacks Statistics Modification Response received from MAC
+*
+* @details
+*
+*    Function : unpackDuMacStatsModificationRsp
+*
+*    Functionality:
+*         Unpacks Statistics Modification Response received from MAC
+*
+* @params[in] Pointer to Handler
+*             Post structure pointer
+*             Message Buffer
+* @return ROK     - success
+*         RFAILED - failure
+*
+* ****************************************************************/
+uint8_t unpackDuMacStatsModificationRsp(MacDuStatsModificationRspFunc func, Pst *pst, Buffer *mBuf)
+{
+    if(pst->selector == ODU_SELECTOR_LWLC)
+    {
+       MacStatsModificationRsp *statsModificationRsp=NULLP;
+
+       /* unpack the address of the structure */
+       CMCHKUNPK(oduUnpackPointer, (PTR *)&statsModificationRsp, mBuf);
+       ODU_PUT_MSG_BUF(mBuf);
+       return (*func)(pst, statsModificationRsp);
+    }
+    else
+    {
+       /* Nothing to do for other selectors */
+       DU_LOG("\nERROR  -->  DU APP : Only LWLC supported for Statistics Modification Response ");
+       ODU_PUT_MSG_BUF(mBuf);
+    }
+
+    return RFAILED;
+}
+
 /**********************************************************************
   End of file
  **********************************************************************/
index 9450cac..9631cc5 100644 (file)
@@ -94,6 +94,8 @@
 #define EVENT_MAC_STATISTICS_IND     231
 #define EVENT_MAC_STATS_DELETE_REQ   232
 #define EVENT_MAC_STATS_DELETE_RSP   233
+#define EVENT_MAC_STATISTICS_MODIFY_REQ     234
+#define EVENT_MAC_STATISTICS_MODIFY_RSP     235
 
 #define BSR_PERIODIC_TIMER_SF_10 10
 #define BSR_RETX_TIMER_SF_320 320
@@ -1924,6 +1926,9 @@ typedef struct macStatsDeleteRsp
    MacStatsDeleteInfo statsGrpDelInfo[MAX_NUM_STATS_GRP]; /*list of the deletion statuses for specific actions */
 }MacStatsDeleteRsp;
 
+typedef struct macStatsReq MacStatsModificationReq;
+typedef struct macStatsRsp MacStatsModificationRsp;
+
 /****************** FUNCTION POINTERS ********************************/
 
 /* DL broadcast req from DU APP to MAC*/
@@ -2103,6 +2108,16 @@ typedef uint8_t (*MacDuStatsDeleteRspFunc) ARGS((
          Pst *pst,
          MacStatsDeleteRsp *statsDeleteRsp));
 
+/* Statitics Modification Request from DU APP to MAC */
+typedef uint8_t (*DuMacStatsModificationReqFunc) ARGS((
+      Pst *pst,
+      MacStatsModificationReq *statsModificationReq));
+
+/* Statistics Modification Response from MAC to DU APP */
+typedef uint8_t (*MacDuStatsModificationRspFunc) ARGS((
+      Pst *pst,
+      MacStatsModificationRsp *statsModificationRsp));
+
 /******************** FUNCTION DECLARATIONS ********************************/
 uint8_t packMacCellUpInd(Pst *pst, OduCellId *cellId);
 uint8_t unpackMacCellUpInd(DuMacCellUpInd func, Pst *pst, Buffer *mBuf);
@@ -2244,6 +2259,15 @@ uint8_t packDuMacStatsDeleteRsp(Pst *pst, MacStatsDeleteRsp *statsDeleteRsp);
 uint8_t DuProcMacStatsDeleteRsp(Pst *pst, MacStatsDeleteRsp *statsDeleteRsp);
 uint8_t unpackDuMacStatsDeleteRsp(MacDuStatsDeleteRspFunc func, Pst *pst, Buffer *mBuf);
 
+uint8_t packDuMacStatsModificationReq(Pst *pst, MacStatsModificationReq *statsModificationReq);
+uint8_t MacProcStatsModificationReq(Pst *pst, MacStatsModificationReq *statsModificationReq);
+uint8_t unpackMacStatsModificationReq(DuMacStatsModificationReqFunc func, Pst *pst, Buffer *mBuf);
+
+uint8_t packDuMacStatsModificationRsp(Pst *pst, MacStatsModificationRsp *statsModificationRsp);
+uint8_t DuProcMacStatsModificationRsp(Pst *pst, MacStatsModificationRsp *statsModificationRsp);
+uint8_t unpackDuMacStatsModificationRsp(MacDuStatsModificationRspFunc func, Pst *pst, Buffer *mBuf);
+
+
 #endif
 
 
index 985d7bb..769ff9d 100644 (file)
@@ -56,6 +56,8 @@
 #define EVENT_STATISTICS_IND_TO_MAC  37
 #define EVENT_STATISTICS_DELETE_REQ_TO_SCH  38
 #define EVENT_STATISTICS_DELETE_RSP_TO_MAC  39
+#define EVENT_STATISTICS_MODIFY_REQ_TO_SCH  40
+#define EVENT_STATISTICS_MODIFY_RSP_TO_MAC  41
 
 /*macros*/
 #define MAX_SSB_IDX 1 /* forcing it as 1 for now. Right value is 64 */
@@ -2263,6 +2265,9 @@ typedef struct schStatsReq
    SchStatsGrpInfo   statsGrpList[MAX_NUM_STATS_GRP];
 }SchStatsReq;
 
+typedef struct schStatsReq SchStatsModificationReq;
+typedef struct schStatsRsp SchStatsModificationRsp;
+
 /* Statistics Response from SCH to MAC */
 typedef struct schStatsGrpRejected
 {
index 57b751c..b1b350a 100644 (file)
@@ -1579,6 +1579,116 @@ uint8_t e2ProcStatsDeleteRsp(MacStatsDeleteRsp *statsDeleteRsp)
    return ROK;
 }
 
+/*******************************************************************
+ *
+ * @brief Fill RIC Subscription datils in MAC Statistics 
+ * ModificationRequest
+ *
+ * @details
+ *
+ *    Function : fillRicSubsInMacStatsModificationReq
+ *
+ *    Functionality: Fill RIC Subscription datils in MAC 
+ * Modification Statistics Request
+ *    [Step -1] Generate subscription ID using RIC Request ID and 
+ *    RAN Function ID
+ *    [Step -2] Check all the action staus of each action present
+ *    in the ric subscription. If action is CONFIG_MOD then fill
+ *    the information in stats group list.
+ *    [Step -3] Fill group related information in stats modification 
+ *    req's in stats group list
+ *    [Step -4] fill measurement information in stats group list
+ *    [Step -5] If the number of stats which needs to modify is 
+ *    greater then zero then return ROK else return RFAILED
+ *
+ * @params[in] MAC Statistics Modification Request to be filled
+ *             RIC Subscription Info
+ *
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t fillRicSubsInMacStatsModificationReq(MacStatsModificationReq *macStatsModificationReq, RicSubscription* ricSubscriptionInfo)
+{
+   uint8_t    grpIdx = 0;
+   uint8_t statsModifyReqIdx = 0;
+   uint64_t   subscriptionId = 0;
+   CmLList *node = NULLP;
+   ActionInfo *actionDb = NULLP;
+   CmLList *actionNode = NULLP;
+   MeasurementInfo *measInfo = NULLP;
+   ActionDefFormat1 *format1Action = NULLP;
+
+   /* [Step -1] */
+   encodeSubscriptionId(&subscriptionId, ricSubscriptionInfo->ranFuncId, ricSubscriptionInfo->requestId);
+
+   macStatsModificationReq->subscriptionId = subscriptionId;
+   CM_LLIST_FIRST_NODE(&ricSubscriptionInfo->actionSequence, actionNode);
+   while(actionNode)
+   {
+      actionDb = (ActionInfo*)(actionNode->node);
+      /* [Step -2] */
+      if(actionDb->action == CONFIG_MOD)
+      {
+         /* [Step -3] */
+         macStatsModificationReq->statsGrpList[grpIdx].groupId = actionDb->actionId;
+         switch(actionDb->definition.formatType)
+         {
+            case 1:
+               {
+                  format1Action = &actionDb->definition.choice.format1;
+                  macStatsModificationReq->statsGrpList[grpIdx].periodicity = format1Action->granularityPeriod;
+
+                  statsModifyReqIdx = 0;
+                  node = cmLListFirst(&format1Action->measurementInfoList);
+                  while(node)
+                  {
+                     /* [Step -4] */
+                     measInfo = (MeasurementInfo *)(node->node);
+                     switch(measInfo->measurementTypeId)
+                     {
+                        case 1:
+                           {
+                              macStatsModificationReq->statsGrpList[grpIdx].statsList[statsModifyReqIdx++] = MAC_DL_TOTAL_PRB_USAGE;
+                              break;
+                           }
+                        case 2:
+                           {
+                              macStatsModificationReq->statsGrpList[grpIdx].statsList[statsModifyReqIdx++] = MAC_UL_TOTAL_PRB_USAGE;
+                              break;
+                           }
+                        default:
+                           {
+                              DU_LOG("\nERROR  -->  E2AP : Invalid measurement name");
+                              break;
+                           }
+                     }
+                     node = node->next;
+                  }
+                  macStatsModificationReq->statsGrpList[grpIdx].numStats = statsModifyReqIdx;
+                  break;
+               }
+            default:
+               {
+                  DU_LOG("\nERROR  -->  E2AP : fillRicSubsInMacStatsModificationReq: Only Action Definition Format 1 supported");
+                  break;
+               }
+         }
+         if(macStatsModificationReq->statsGrpList[grpIdx].numStats)
+            grpIdx++;
+      }
+      actionNode = actionNode->next;
+   }
+
+   /* [Step -5] */
+   macStatsModificationReq->numStatsGroup = grpIdx;
+   if(macStatsModificationReq->numStatsGroup)
+   {
+      return ROK;
+   }
+   return RFAILED;
+}
+
 /**********************************************************************
   End of file
  **********************************************************************/
index 9952474..85447f2 100644 (file)
@@ -534,6 +534,7 @@ void deleteMeasuredValueList(CmLListCp *measuredValueList);
 void removeE2NodeInformation();
 void encodeSubscriptionId(uint64_t *subscriptionId, uint16_t ranFuncId, RicRequestId ricReqId);
 uint8_t e2ProcStatsDeleteRsp(MacStatsDeleteRsp *statsDeleteRsp);
+uint8_t fillRicSubsInMacStatsModificationReq(MacStatsModificationReq *macStatsModReq, RicSubscription* ricSubscriptionInfo);
 
 /**********************************************************************
   End of file
index a1112d0..0338f74 100644 (file)
@@ -302,6 +302,11 @@ void callFlowduActvTsk(Pst *pst)
                      strcpy(message,"EVENT_MAC_STATS_DELETE_RSP");
                      break;
                   }
+               case EVENT_MAC_STATISTICS_MODIFY_RSP:
+                  {
+                     strcpy(message,"EVENT_MAC_STATISTICS_MODIFY_RSP");
+                     break;
+                  }
                default:
                   {
                      strcpy(message,"Invalid Event");
@@ -612,6 +617,11 @@ uint8_t duActvTsk(Pst *pst, Buffer *mBuf)
                      ret = unpackDuMacStatsDeleteRsp(DuProcMacStatsDeleteRsp, pst, mBuf);
                      break;
                   }
+               case EVENT_MAC_STATISTICS_MODIFY_RSP:
+                  {
+                     ret = unpackDuMacStatsModificationRsp(DuProcMacStatsModificationRsp, pst, mBuf);
+                     break;
+                  }
                default:
                   {
                      DU_LOG("\nERROR  -->  DU_APP : Invalid event received at duActvTsk from ENTMAC");
index 39b2702..1089a5e 100644 (file)
@@ -118,6 +118,13 @@ DuMacStatsDeleteReqFunc packMacStatsDeleteReqOpts[]=
    packDuMacStatsDeleteReq           /* Light weight-loose coupling */
 };
 
+DuMacStatsModificationReqFunc packMacStatsModificationReqOpts[]=
+{
+   packDuMacStatsModificationReq,          /* Loose Coupling */
+   MacProcStatsModificationReq,            /* Tight Coupling */
+   packDuMacStatsModificationReq           /* Light weight-loose coupling */
+};
+
 /**************************************************************************
  * @brief Function to fill configs required by RLC
  *
@@ -2436,6 +2443,144 @@ uint8_t BuildAndSendStatsDeleteReq(RicSubscription *ricSubscriptionInfo)
    return ROK;
 }
 
+ /*******************************************************************
+ *
+ * @brief Send Statistics Modification request to MAC
+ *
+ * @details
+ *
+ *    Function : BuildAndSendStatsModificationReqToMac()
+ *
+ *    Functionality: Send Statistics Modification Request To Mac
+ *
+ * @params[in] Ric subscription info
+ *
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t BuildAndSendStatsModificationReqToMac(RicSubscription *ricSubscriptionInfo)
+{
+   Pst pst;
+   MacStatsModificationReq *macStatsModificationReq = NULLP;
+
+   /* Fill MAC statistics modification request */
+   DU_ALLOC_SHRABL_BUF(macStatsModificationReq, sizeof(MacStatsModificationReq));
+   if(macStatsModificationReq == NULLP)
+   {
+      DU_LOG("\nERROR  -->  DU_APP : Memory allocation failed for macStatsModificationReq in BuildAndSendStatsModificationReqToMac");
+      return RFAILED;
+   }
+
+   /* Fill E2 Subscription Info in MAC Statistics Modification Request and send to MAC */
+   if(fillRicSubsInMacStatsModificationReq(macStatsModificationReq, ricSubscriptionInfo) == ROK)
+   {
+      DU_LOG("\nDEBUG  -->  DU_APP: Sending Statistics Modification Request to MAC ");
+      FILL_PST_DUAPP_TO_MAC(pst, EVENT_MAC_STATISTICS_MODIFY_REQ);
+
+      if( (*packMacStatsModificationReqOpts[pst.selector])(&pst, macStatsModificationReq) == ROK)
+         return ROK;
+
+      DU_LOG("\nERROR  -->  DU_APP: Failed to send Statistics Modification Request to MAC");
+   }
+
+   DU_LOG("\nERROR  -->  DU_APP: No Statistics group found valid. Hence statistics Modification request is not sent to MAC");
+   DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, macStatsModificationReq, sizeof(MacStatsModificationReq));
+   return RFAILED;
+}
+
+/*******************************************************************
+ *
+ * @brief Send Statistics Modification request to DU layers
+ *
+ * @details
+ *
+ *    Function : BuildAndSendStatsModificationReq()
+ *
+ *    Functionality: Check if there is an update in statistics
+ *       reporting configuration. If so, send the update Modification to
+ *       respective layer.
+ *
+ * @params[in] Subscription Info
+ *
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t BuildAndSendStatsModificationReq(RicSubscription *ricSubscriptionInfo)
+{
+   /* Build and sent subscription information to MAC in Statistics Modification Request */
+   if(BuildAndSendStatsModificationReqToMac(ricSubscriptionInfo) != ROK)
+   {
+      DU_LOG("\nERROR  -->  DU_APP : Failed at BuildAndSendStatsModificationReqToMac()");
+      return RFAILED;
+   }
+
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Process statistics modification response from MAC
+ *
+ * @details
+ *
+ *    Function : DuProcMacStatsModificationRsp
+ *
+ *    Functionality: Processes statistics modification configuration 
+ *       response from MAC. If configuration is succsessful, DUAPP starts
+ *       reporting period timer for this subscription request
+ *       from RIC
+ *
+ * @params[in]
+ *    PST structure
+ *    MAC stats modification rsp
+ *
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t DuProcMacStatsModificationRsp(Pst *pst, MacStatsModificationRsp *statsModificationRsp)
+{
+   uint8_t ret = RFAILED;
+   DU_LOG("\nINFO  -->  DU_APP : DuProcMacStatsModificationRsp: Received Statistics Modification Response from MAC");
+
+   if(statsModificationRsp)
+   {
+#ifdef DEBUG_PRINT
+      uint8_t idx = 0;
+      DU_LOG("\n  Subscription Id [%ld]", statsModificationRsp->subscriptionId);
+
+      DU_LOG("\n  Number of Accepted Groups [%d]", statsModificationRsp->numGrpAccepted);
+      for(idx=0; idx<statsModificationRsp->numGrpAccepted; idx++)
+      {
+         DU_LOG("\n    Group Id [%d]", statsModificationRsp->statsGrpAcceptedList[idx]);
+      }
+
+      DU_LOG("\n  Number of Rejected Groups [%d]", statsModificationRsp->numGrpRejected);
+      for(idx=0; idx<statsModificationRsp->numGrpRejected; idx++)
+      {
+         DU_LOG("\n    Group Id [%d]", statsModificationRsp->statsGrpRejectedList[idx].groupId);
+      }
+#endif
+#if 0
+      /*TODO*/
+      /* Check the list of accepted and rejected statistics group and send
+       * Ric subscription modification response/failure accordingly */
+      if((ret = e2ProcStatsModificationRsp(statsModificationRsp)) != ROK)
+      {
+         DU_LOG("\nERROR  -->  DU_APP : DuProcMacStatsModificationRsp: Failed in %s at line %d", __func__, __LINE__);
+      }
+#endif
+      DU_FREE_SHRABL_BUF(pst->region, pst->pool, statsModificationRsp, sizeof(MacStatsModificationRsp));
+   }
+   else
+   {
+      DU_LOG("\nERROR  -->  DU_APP : DuProcMacStatsModificationRsp: Received NULL Pointer");
+   }
+   return ret;
+}
+
 /**********************************************************************
   End of file
  **********************************************************************/