+/*******************************************************************
+ *
+ * @brief Fill RIC Subscription datils in MAC Statistics Request
+ *
+ * @details
+ *
+ * Function : fillRicSubsInMacStatsReq
+ *
+ * Functionality: Fill RIC Subscription datils in MAC Statistics
+ * Request
+ *
+ * @params[in] MAC Statistics Request to be filled
+ * RIC Subscription Info
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t fillRicSubsInMacStatsReq(MacStatsReq *macStatsReq, RicSubscription* ricSubscriptionInfo)
+{
+ uint8_t actionIdx = 0, grpIdx = 0, statsIdx = 0;
+ uint64_t subscriptionId = 0;
+ ActionInfo *actionDb = NULLP;
+ ActionDefFormat1 *format1Action = NULLP;
+
+ /* Generate subscription ID using RIC Request ID and RAN Function ID */
+ encodeSubscriptionId(&subscriptionId, ricSubscriptionInfo->ranFuncId, ricSubscriptionInfo->requestId);
+
+ macStatsReq->subscriptionId = subscriptionId;
+ for(actionIdx = 0; actionIdx < MAX_RIC_ACTION; actionIdx++)
+ {
+ if(ricSubscriptionInfo->actionSequence[actionIdx].action == CONFIG_ADD)
+ {
+ actionDb = &ricSubscriptionInfo->actionSequence[actionIdx];
+ macStatsReq->statsGrpList[grpIdx].groupId = actionDb->actionId;
+ switch(actionDb->definition.formatType)
+ {
+ case 1:
+ {
+ format1Action = &actionDb->definition.choice.format1;
+ macStatsReq->statsGrpList[grpIdx].periodicity = format1Action->granularityPeriod;
+
+ CmLList *node = NULLP;
+ MeasurementInfo *measInfo = NULLP;
+ statsIdx = 0;
+ /* Update DL PRB Usage for all stats group which requested for DL Total PRB Usage */
+ node = cmLListFirst(&format1Action->measurementInfoList);
+ while(node)
+ {
+ measInfo = (MeasurementInfo *)(node->node);
+ switch(measInfo->measurementTypeId)
+ {
+ case 1:
+ {
+ macStatsReq->statsGrpList[grpIdx].statsList[statsIdx++] = MAC_DL_TOTAL_PRB_USAGE;
+ break;
+ }
+ case 2:
+ {
+ macStatsReq->statsGrpList[grpIdx].statsList[statsIdx++] = MAC_UL_TOTAL_PRB_USAGE;
+ break;
+ }
+ default:
+ {
+ DU_LOG("\nERROR --> E2AP : Invalid measurement name");
+ break;
+ }
+ }
+ node = node->next;
+ }
+ macStatsReq->statsGrpList[grpIdx].numStats = statsIdx;
+ break;
+ }
+ default:
+ {
+ DU_LOG("\nERROR --> E2AP : fillRicSubsInMacStatsReq: Only Action Definition Format 1 supported");
+ break;
+ }
+ }
+ if(macStatsReq->statsGrpList[grpIdx].numStats)
+ grpIdx++;
+ }
+ }
+
+ macStatsReq->numStatsGroup = grpIdx;
+ if(macStatsReq->numStatsGroup)
+ {
+ return ROK;
+ }
+ return RFAILED;
+}
+
+/*******************************************************************
+ *
+ * @brief Rejects all actions received in a subscription request
+ *
+ * @details
+ *
+ * Function : duRejectAllStatsGroup
+ *
+ * Functionality: Rejects all actions received in a subscription
+ * request by :
+ * a. Removing the subscription entry from RAN function
+ * b. Sending RIC Subscription Failure to RIC with appropriate
+ * cause of failure
+ *
+ * @params[in] RAN Function DB
+ * Subscription entry in RAN Function subscription list
+ * Statistics Response from MAC
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t rejectAllStatsGroup(RanFunction *ranFuncDb, CmLList *ricSubscriptionNode, MacStatsRsp *statsRsp)
+{
+ uint8_t ret = ROK;
+ RicRequestId requestId;
+ E2FailureCause failureCause;
+
+ /* Delete subcription from RAN Function */
+ memcpy(&requestId, &((RicSubscription *)ricSubscriptionNode->node)->requestId, sizeof(RicRequestId));
+ cmLListDelFrm(&ranFuncDb->subscriptionList, ricSubscriptionNode);
+ DU_FREE(ricSubscriptionNode->node, sizeof(RicSubscription));
+ DU_FREE(ricSubscriptionNode, sizeof(CmLList));
+
+ convertDuCauseToE2Cause(statsRsp->statsGrpRejectedList[0].cause, &failureCause);
+
+ /* Send RIC subscription failure to RIC */
+ ret = BuildAndSendRicSubscriptionFailure(requestId, ranFuncDb->id, failureCause);
+ return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Process statistics response from MAC
+ *
+ * @details
+ *
+ * Function : e2ProcStatsRsp
+ *
+ * Functionality: Processes statistics configuration response
+ * from MAC. If configuration is succsessful, DUAPP starts
+ * reporting period timer for this subscription request
+ * from RIC
+ *
+ * @params[in] Statistics response received from MAC
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t e2ProcStatsRsp(MacStatsRsp *statsRsp)
+{
+ uint8_t idx = 0;
+ uint8_t actionId = 0;
+ uint32_t reportingPeriod = 0;
+ RanFunction *ranFuncDb = NULLP;
+ CmLList *ricSubscriptionNode = NULLP;
+ RicSubscription *ricSubscriptionInfo = NULLP;
+ ActionInfo *actionInfoDb = NULLP;
+ PendingSubsRspInfo *pendingSubsRsp = NULLP;
+
+ /* Fetch RAN Function and Subscription DB using subscription Id received in statistics response */
+ if(fetchSubsInfoFromSubsId(statsRsp->subscriptionId, &ranFuncDb, &ricSubscriptionNode, &ricSubscriptionInfo) != ROK)
+ {
+ DU_LOG("\nERROR --> E2AP : DuProcMacStatsRsp: Failed to fetch subscriprtion details");
+ return RFAILED;
+ }
+
+ /* Fetch pre-stored statistics response info by DU APP */
+ for(idx=0; idx<ranFuncDb->numPendingSubsRsp; idx++)
+ {
+ if((ranFuncDb->pendingSubsRspInfo[idx].requestId.requestorId == ricSubscriptionInfo->requestId.requestorId) &&
+ (ricSubscriptionInfo->requestId.instanceId == ricSubscriptionInfo->requestId.instanceId))
+ {
+ pendingSubsRsp = &ranFuncDb->pendingSubsRspInfo[idx];
+ break;
+ }
+ }
+
+ /* If no action is accepted
+ * a. Remove subcription entry from RAN Function
+ * b. Send RIC subscription failure */
+ if(statsRsp->numGrpAccepted == 0)
+ {
+ rejectAllStatsGroup(ranFuncDb, ricSubscriptionNode, statsRsp);
+ }
+ else
+ {
+ /* Start RIC Subscription reporting timer */
+ switch(ricSubscriptionInfo->eventTriggerDefinition.formatType)
+ {
+ case 1:
+ {
+ reportingPeriod = ricSubscriptionInfo->eventTriggerDefinition.choice.format1.reportingPeriod;
+
+ /* Save the start time of reporting period */
+ storeReportStartTime(&ricSubscriptionInfo->eventTriggerDefinition.choice.format1.startTime);
+ break;
+ }
+ default:
+ {
+ DU_LOG("\nERROR --> E2AP : Invalid event trigger format of RIC subscription");
+ return RFAILED;
+ }
+ }
+ if(duChkTmr((PTR)ricSubscriptionInfo, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR) != true)
+ {
+ duStartTmr((PTR)ricSubscriptionInfo, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR, reportingPeriod);
+ }
+ else
+ {
+ DU_LOG("\nERROR --> E2AP : RIC Subscription reporting timer already running for RIC Subscription");
+ return RFAILED;
+ }
+
+
+ /* If even 1 action is accepted :
+ *
+ * For accepted groups:
+ * Mark subscribed-action's -> action = CONFIG_UNKNOWN
+ * Add to accepted-action-list of subscription response
+ */
+ for(idx=0; idx<statsRsp->numGrpAccepted; idx++)
+ {
+ actionInfoDb = NULLP;
+
+ actionId = statsRsp->statsGrpAcceptedList[idx];
+ actionInfoDb = fetchActionInfoFromActionId(actionId, ricSubscriptionInfo);
+ if(actionInfoDb && (actionInfoDb->action == CONFIG_ADD))
+ {
+ actionInfoDb->action = CONFIG_UNKNOWN;
+ pendingSubsRsp->acceptedActionList[pendingSubsRsp->numOfAcceptedActions++] = actionId;
+ }
+ }
+
+ /* For rejected groups:
+ * Remove entry from DU's RAN Function->subscription->actionList
+ * Add to rejected-action-list in subscription response
+ */
+ for(idx=0; idx<statsRsp->numGrpRejected; idx++)
+ {
+ actionId = statsRsp->statsGrpRejectedList[idx].groupId;
+ if(ricSubscriptionInfo->actionSequence[actionId].actionId == actionId)
+ {
+ memset(&ricSubscriptionInfo->actionSequence[actionId], 0, sizeof(ActionInfo));
+ ricSubscriptionInfo->numOfActions--;
+
+ pendingSubsRsp->rejectedActionList[pendingSubsRsp->numOfRejectedActions].id = actionId;
+ convertDuCauseToE2Cause(statsRsp->statsGrpRejectedList[idx].cause, \
+ &pendingSubsRsp->rejectedActionList[pendingSubsRsp->numOfRejectedActions].failureCause);
+ pendingSubsRsp->numOfRejectedActions++;
+ }
+ }
+
+ /* Send subscription response with accepted and rejected action lists to RIC */
+ BuildAndSendRicSubscriptionRsp(pendingSubsRsp);
+ }
+ memset(pendingSubsRsp, 0, sizeof(PendingSubsRspInfo));
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Extract and store statistics received from DU layers
+ *
+ * @details
+ *
+ * Function : e2ProcStatsInd
+ *
+ * Functionality: Extract statistics received from DU layers
+ * and store in respective RAN function's subscription's
+ * action
+ *
+ * @params[in] Statistics Indication message received from MAC
+ * @return ROK-success
+ * RFAILED-failure
+ *
+ * ****************************************************************/
+uint8_t e2ProcStatsInd(MacStatsInd *statsInd)
+{
+ uint8_t statsIdx = 0;
+ RanFunction *ranFuncDb = NULLP;
+ CmLList *ricSubscriptionNode = NULLP;
+ RicSubscription *ricSubscriptionInfo = NULLP;
+ ActionInfo *actionInfo = NULLP;
+ ActionDefFormat1 *actionFormat = NULLP;
+ char e2MeasTypeName[STRING_SIZE_150_BYTES] = "";
+ MeasurementInfo *measInfo = NULLP;
+ CmLList *measInfoNode = NULLP;
+ double *measValue = NULLP;
+ CmLList *measValueNode = NULLP;
+
+ /* TODO : When stats indication is received
+ * DU APP searches for the message type in E2AP RIC subscription
+ * database and stores in the value in the list of subscribed measurements
+ *
+ * This will be implemented in next gerrit.
+ */
+
+ /* Fetch RAN Function and Subscription DB using subscription Id received
+ * in statistics response */
+ if(fetchSubsInfoFromSubsId(statsInd->subscriptionId, &ranFuncDb, &ricSubscriptionNode, &ricSubscriptionInfo) != ROK)
+ {
+ DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Failed to fetch subscriprtion details");
+ return RFAILED;
+ }
+
+ /* Fetch RIC subscription's action DB */
+ actionInfo = fetchActionInfoFromActionId(statsInd->groupId, ricSubscriptionInfo);
+ if(actionInfo == NULLP)
+ {
+ DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Failed to fetch action ID [%d]", statsInd->groupId);
+ return RFAILED;
+ }
+
+ /* Check Action format */
+ switch(actionInfo->definition.formatType)
+ {
+ case 1:
+ {
+ actionFormat = &actionInfo->definition.choice.format1;
+ break;
+ }
+ default:
+ {
+ DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Action Format [%d] is not supported", \
+ actionInfo->definition.formatType);
+ return RFAILED;
+ }
+ }
+
+ /* Fetch each Measurement info from action info and store its reported value in DB */
+ for(statsIdx = 0; statsIdx < statsInd->numStats; statsIdx++)
+ {
+ memset(e2MeasTypeName, 0, STRING_SIZE_150_BYTES);
+ measInfo = NULLP;
+ measInfoNode = NULLP;
+
+ /* Convert Measurement type from MAC-supported format to E2-supported format */
+ if(convertMacMeasTypeToE2MeasType(statsInd->measuredStatsList[statsIdx].type, e2MeasTypeName) != ROK)
+ {
+ DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Failed to convert measurement type from MAC-supported\
+ MAC-supported format to E2-supported format");
+ continue;
+ }
+
+ /* Fetch Measurement Info using E2-supported measurement type name */
+ measInfo = fetchMeasInfoFromMeasTypeName(e2MeasTypeName, &actionFormat->measurementInfoList, &measInfoNode);
+ if(measInfo == NULLP)
+ {
+ DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Measurement Type Name [%s] not found", e2MeasTypeName);
+ continue;
+ }
+
+ /* Store the measurement value in the measurement info DB fetched */
+ DU_ALLOC(measValue, sizeof(double));
+ if(!measValue)
+ {
+ DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Memory allocation failed at line [%d]", __LINE__);
+ return RFAILED;
+ }
+ *measValue = statsInd->measuredStatsList[statsIdx].value;
+
+ DU_ALLOC(measValueNode, sizeof(CmLList));
+ if(!measValueNode)
+ {
+ DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Memory allocation failed at line [%d]", __LINE__);
+ DU_FREE(measValue, sizeof(double));
+ return RFAILED;
+ }
+ measValueNode->node = (PTR) measValue;
+ cmLListAdd2Tail(&measInfo->measuredValue, measValueNode);
+ }
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Handle RIC Subscription reporting timer expry
+ *
+ * @details
+ *
+ * Function : E2apHdlRicSubsReportTmrExp
+ *
+ * Functionality: On expiry of RIC subscription reporting
+ * timer expiry, RIC indication is sent for all actions
+ * in RIC subscription
+ *
+ * @params[in] RIC subscription DB
+ * @return void
+ *
+ * ****************************************************************/
+void E2apHdlRicSubsReportTmrExp(RicSubscription *ricSubscription)
+{
+ uint8_t actionIdx = 0;
+ uint32_t reportingPeriod = 0;
+
+ for(actionIdx = 0; actionIdx < MAX_RIC_ACTION; actionIdx++)
+ {
+ if(ricSubscription->actionSequence[actionIdx].actionId >= 0)
+ {
+ BuildAndSendRicIndication(ricSubscription, &ricSubscription->actionSequence[actionIdx]);
+ }
+ }
+
+ /* Start RIC Subscription reporting timer again */
+ switch(ricSubscription->eventTriggerDefinition.formatType)
+ {
+ case 1:
+ {
+ reportingPeriod = ricSubscription->eventTriggerDefinition.choice.format1.reportingPeriod;
+ /* Save the start time of reporting period */
+ storeReportStartTime(&ricSubscription->eventTriggerDefinition.choice.format1.startTime);
+ break;
+ }
+ default:
+ return;
+ }
+ if(duChkTmr((PTR)ricSubscription, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR) != true)
+ {
+ duStartTmr((PTR)ricSubscription, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR, reportingPeriod);
+ }
+ else
+ {
+ DU_LOG("\nERROR --> E2AP : Failed in %s at line %d", __func__, __LINE__);
+ return;
+ }
+}
+
+/******************************************************************
+ *
+ * @brief Search E2 node component with the help of action type
+ *
+ * @details
+ *
+ * Function : fetchE2NodeComponentInfo
+ *
+ * Functionality: Search E2 node component with the help of action type
+ *
+ * @params[in]
+ * Type of interface
+ * Component action type
+ * Pointer to E2 component node to be searched
+ * @return CmLList
+ *
+ * ****************************************************************/
+
+E2NodeComponent *fetchE2NodeComponentInfo(InterfaceType interfaceType, uint8_t componentActionType, CmLList **e2ComponentNode)
+{
+ E2NodeComponent *e2NodeComponentInfo=NULLP;
+
+ if(duCb.e2apDb.e2NodeComponentList.count)
+ {
+ CM_LLIST_FIRST_NODE(&duCb.e2apDb.e2NodeComponentList, *e2ComponentNode);
+ while(*e2ComponentNode)
+ {
+ e2NodeComponentInfo = (E2NodeComponent*)((*e2ComponentNode)->node);
+ if((e2NodeComponentInfo->interfaceType == interfaceType) && (e2NodeComponentInfo->componentActionType == componentActionType))
+ {
+
+ break;
+ }
+
+ *e2ComponentNode = (*e2ComponentNode)->next;
+ e2NodeComponentInfo = NULLP;
+ }
+ }
+ return e2NodeComponentInfo;
+}
+
+/*******************************************************************
+ *
+ * @brief add or modify E2NodeComponent list
+ *
+ * @details
+ *
+ * Function : addOrModifyE2NodeComponent
+ *
+ * Functionality: add or modify E2NodeComponent list
+ *
+ * @parameter
+ * Type of interface
+ * Component action type
+ * boolean variable to check req or rsp msg type
+ * Size of buffer which needs to be store
+ * buffer string which needs to be store
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ ******************************************************************/
+
+uint8_t addOrModifyE2NodeComponent(InterfaceType interfaceType, uint8_t action, bool reqPart, uint8_t bufSize, char *bufString)
+{
+ E2NodeComponent *e2NodeComponentInfo= NULL;
+ CmLList *node = NULLP;
+
+ if(reqPart == true)
+ {
+ DU_ALLOC(e2NodeComponentInfo, sizeof(E2NodeComponent));
+ if(!e2NodeComponentInfo)
+ {
+ DU_LOG("\nERROR --> E2AP : Memory allocation failed for e2NodeComponentInfo in %s",__func__);
+ return RFAILED;
+ }
+ e2NodeComponentInfo->interfaceType =interfaceType;
+ e2NodeComponentInfo->componentId=duCfgParam.duId;
+ e2NodeComponentInfo->componentActionType = action;
+ e2NodeComponentInfo->reqBufSize = bufSize;
+
+ DU_ALLOC(e2NodeComponentInfo->componentRequestPart, bufSize);
+ if(e2NodeComponentInfo->componentRequestPart == NULLP)
+ {
+ DU_LOG("\nERROR --> E2AP : Memory allocation failed for componentRequestPart");
+ DU_FREE(e2NodeComponentInfo, sizeof(E2NodeComponent));
+ return RFAILED;
+ }
+ memcpy(e2NodeComponentInfo->componentRequestPart, bufString, e2NodeComponentInfo->reqBufSize);
+ DU_ALLOC(node, sizeof(CmLList));
+ if(node)
+ {
+ node->node = (PTR) e2NodeComponentInfo;
+ cmLListAdd2Tail(&duCb.e2apDb.e2NodeComponentList, node);
+ }
+ else
+ {
+ DU_LOG("\nERROR --> E2AP : Memory allocation failed for e2NodeComponentList node");
+ DU_FREE(e2NodeComponentInfo->componentRequestPart, bufSize);
+ DU_FREE(e2NodeComponentInfo, sizeof(E2NodeComponent));
+ return RFAILED;
+ }
+ }
+ else
+ {
+ if(duCb.e2apDb.e2NodeComponentList.count)
+ {
+ e2NodeComponentInfo = fetchE2NodeComponentInfo(interfaceType, action, &node);
+ if(e2NodeComponentInfo->componentRequestPart== NULLP)
+ {
+ DU_LOG("\nERROR --> E2AP : E2 node Component request part is not present");
+ return RFAILED;
+ }
+
+ e2NodeComponentInfo->rspBufSize = bufSize;
+ DU_ALLOC(e2NodeComponentInfo->componentResponsePart, bufSize);
+ if(e2NodeComponentInfo->componentResponsePart == NULLP)
+ {
+ DU_LOG("\nERROR --> E2AP : Memory allocation failed to store the encoding of rsp");
+ return RFAILED;
+ }
+ memcpy(e2NodeComponentInfo->componentResponsePart, bufString, e2NodeComponentInfo->rspBufSize);
+ return ROK;
+ }
+ else
+ {
+ DU_LOG("\nERROR --> E2AP : Unable to find the node");
+ return RFAILED;
+ }
+ }
+ return ROK;
+}
+