1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
5 # Licensed under the Apache License, Version 2.0 (the "License"); #
6 # you may not use this file except in compliance with the License. #
7 # You may obtain a copy of the License at #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
11 # Unless required by applicable law or agreed to in writing, software #
12 # distributed under the License is distributed on an "AS IS" BASIS, #
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
14 # See the License for the specific language governing permissions and #
15 # limitations under the License. #
16 ################################################################################
17 *******************************************************************************/
18 #include "common_def.h"
25 #include "du_app_mac_inf.h"
26 #include "du_app_rlc_inf.h"
27 #include "du_e2ap_mgr.h"
28 #include "du_e2_conversions.h"
29 #include "du_e2ap_msg_hdl.h"
33 #include "du_mgr_main.h"
36 /*******************************************************************
38 * @brief Assigns new transaction id to DU initiated procedure
42 * Function : assignTransactionId
44 * Functionality: Assigns new transaction id to a DU initiated
47 * @params[in] Region region
49 * @return ROK - success
52 * ****************************************************************/
53 uint8_t assignTransactionId()
55 uint8_t currTransId = duCb.e2apDb.e2TransInfo.transIdCounter;
57 /* Update to next valid value */
58 duCb.e2apDb.e2TransInfo.transIdCounter++;
59 if(duCb.e2apDb.e2TransInfo.transIdCounter == MAX_NUM_TRANSACTION)
60 duCb.e2apDb.e2TransInfo.transIdCounter = 0;
65 /*******************************************************************
67 * @brief Decode subscription ID
71 * Function : decodeSubscriptionId
73 * Functionality: Decode subscription id to get RAN function ID
76 * @params[in] Subscription ID
77 * RAN Function ID to be extracted
78 * RIC Request ID to be extracted
81 * ****************************************************************/
82 void decodeSubscriptionId(uint64_t subscriptionId, uint16_t *ranFuncId, RicRequestId *ricReqId)
84 /* Extract following from 64 bit subscription-ID :
85 * First 16 MSB is unused
86 * Next 16 MSB = RAN-Function-ID
87 * Next 16 MSB = Requestor-ID in RIC-Request-ID
88 * Last 16 LSB = Instance-ID in RIC-Request-ID
90 ricReqId->instanceId = subscriptionId & 0xFFFF;
91 ricReqId->requestorId = (subscriptionId >> 16) & 0xFFFF;
92 *ranFuncId = (subscriptionId >> 32) & 0xFFFF;
95 /*******************************************************************
97 * @brief Encode subscription ID
101 * Function : encodeSubscriptionId
103 * Functionality: Encode subscription id to get RAN function ID
106 * @params[in] Subscription ID to be encoded
111 * ****************************************************************/
112 void encodeSubscriptionId(uint64_t *subscriptionId, uint16_t ranFuncId, RicRequestId ricReqId)
114 /* Calculate 64 bit subscription-ID :
115 * First 16 MSB is unused
116 * Next 16 MSB = RAN-Function-ID
117 * Next 16 MSB = Requestor-ID in RIC-Request-ID
118 * Last 16 LSB = Instance-ID in RIC-Request-ID
120 *subscriptionId = ricReqId.instanceId;
121 *subscriptionId |= ((uint64_t)ricReqId.requestorId << 16);
122 *subscriptionId |= ((uint64_t)ranFuncId << 32);
125 /*******************************************************************
127 * @brief Stores the current time at the start of reporting period
131 * Function : storeReportStartTime
133 * Functionality: Stores the current time at the start of
136 * @params[in] Start Timer to be stored
139 * ****************************************************************/
140 void storeReportStartTime(ReportStartTime *startTime)
144 gettimeofday(&tv, NULL);
145 startTime->timeInSec = tv.tv_sec;
146 startTime->timeInMilliSec = (tv.tv_usec/1000);
150 /*******************************************************************
152 * @brief Fetch Measurement Info using measurement type name
156 * Function : fetchMeasInfoFromMeasTypeName
158 * Functionality: Fetch Measurement Info using measurement type name
160 * @params[in] Measurement type name to search
161 * Measurement Info list to search from
162 * Measurement Info node found from list
163 * @return Measurement Info DB
165 * ****************************************************************/
166 MeasurementInfo *fetchMeasInfoFromMeasTypeName(char *e2MeasTypeName, CmLListCp *measInfoList, CmLList **measInfoNode)
168 MeasurementInfo *measInfo = NULLP;
170 /* Fetch subscription detail in RAN Function DB */
171 CM_LLIST_FIRST_NODE(measInfoList, *measInfoNode);
174 measInfo = (MeasurementInfo *)((*measInfoNode)->node);
175 if(measInfo && !strcmp(e2MeasTypeName, measInfo->measurementTypeName))
179 *measInfoNode = (*measInfoNode)->next;
185 DU_LOG("\nERROR --> E2AP : fetchMeasInfoFromMeasTypeName: Measurement [%s] not found", e2MeasTypeName);
191 /*******************************************************************
193 * @brief Fetch Action details
197 * Function : fetchActionInfoFromActionId
199 * Functionality: Fetch action details from RIC subscription DB
202 * @params[in] Action ID
203 * RIC Subscription DB
205 * @return Action Info DB
206 * NULL, in case of failure
208 * ****************************************************************/
209 ActionInfo *fetchActionInfoFromActionId(uint8_t actionId, RicSubscription *ricSubscriptionInfo, CmLList ** actionNode)
211 ActionInfo *actionInfoDb = NULLP;
213 CM_LLIST_FIRST_NODE(&ricSubscriptionInfo->actionSequence, *actionNode);
216 actionInfoDb = (ActionInfo*)((*actionNode)->node);
217 if(actionInfoDb && actionInfoDb->actionId == actionId)
221 *actionNode= (*actionNode)->next;
222 actionInfoDb = NULLP;
227 DU_LOG("\nERROR --> E2AP : fetchActionInfoFromActionId: Action Id [%d] not found in \
228 subscription info [Requestor id : %d] [Instance Id : %d]", actionId,\
229 ricSubscriptionInfo->requestId.requestorId, ricSubscriptionInfo->requestId.instanceId);
235 /*******************************************************************
237 * @brief Fetch subscripton DB
241 * Function : fetchSubsInfoFromRicReqId
243 * Functionality: Fetches subscription DB from RAN Function DB
244 * using RIC Request ID
246 * @params[in] RIC Request ID
248 * Pointer to RIC Subscription node to be searched
249 * @return RIC Subscription from RAN Function's subcription list
250 * NULL, in case of failure
252 * ****************************************************************/
253 RicSubscription *fetchSubsInfoFromRicReqId(RicRequestId ricReqId, RanFunction *ranFuncDb, CmLList **ricSubscriptionNode)
255 RicSubscription *ricSubscriptionInfo = NULLP;
257 /* Fetch subscription detail in RAN Function DB */
258 CM_LLIST_FIRST_NODE(&ranFuncDb->subscriptionList, *ricSubscriptionNode);
259 while(*ricSubscriptionNode)
261 ricSubscriptionInfo = (RicSubscription *)((*ricSubscriptionNode)->node);
262 if(ricSubscriptionInfo && (ricSubscriptionInfo->requestId.requestorId == ricReqId.requestorId) &&
263 (ricSubscriptionInfo->requestId.instanceId == ricReqId.instanceId))
267 *ricSubscriptionNode = (*ricSubscriptionNode)->next;
268 ricSubscriptionInfo = NULLP;
271 if(!ricSubscriptionInfo)
273 DU_LOG("\nERROR --> E2AP : fetchSubsInfoFromRicReqId: Subscription not found for Requestor ID [%d] \
274 Instance ID [%d] in RAN Function ID [%d]", ricReqId.requestorId, ricReqId.instanceId, ranFuncDb->id);
277 return ricSubscriptionInfo;
280 /*******************************************************************
282 * @brief Fetches RAN Function DB
286 * Function : fetchRanFuncFromRanFuncId
288 * Functionality: Fetches RAN function DB from E2AP DB using
291 * @params[in] RAN Function ID
292 * @return RAN Function DB
293 * NULL, in case of failure
295 * ****************************************************************/
296 RanFunction *fetchRanFuncFromRanFuncId(uint16_t ranFuncId)
298 RanFunction *ranFuncDb = NULLP;
300 /* Fetch RAN Function DB */
301 if(duCb.e2apDb.ranFunction[ranFuncId-1].id == ranFuncId)
303 ranFuncDb = &duCb.e2apDb.ranFunction[ranFuncId-1];
307 DU_LOG("\nERROR --> E2AP : fetchRanFuncFromRanFuncId: Invalid RAN Function ID[%d]", ranFuncId);
313 /*******************************************************************
315 * @brief Fetches subscription info
319 * Function : fetchSubsInfoFromSubsId
322 * 1. Firstly, RAN Function ID and RIC request ID is extracted
323 * from Subscription ID
324 * 2. Using RAN Function ID, RAN Function DB is searched
325 * 3. Using RIC Request ID, the subscription DB is searched in
328 * @params[in] Subscription ID
330 * RIC Subscription node from RAN Func's Subscription list
334 * ****************************************************************/
335 uint8_t fetchSubsInfoFromSubsId(uint64_t subscriptionId, RanFunction **ranFuncDb, CmLList **ricSubscriptionNode, \
336 RicSubscription **ricSubscriptionInfo)
338 uint16_t ranFuncId = 0;
339 RicRequestId ricReqId;
341 memset(&ricReqId, 0, sizeof(RicRequestId));
343 /* Decode subscription ID o get RIC Request ID and RAN Function ID */
344 decodeSubscriptionId(subscriptionId, &ranFuncId, &ricReqId);
346 /* Fetch RAN Function DB using RAN Function ID */
347 *ranFuncDb = fetchRanFuncFromRanFuncId(ranFuncId);
348 if((*ranFuncDb) == NULLP)
353 /* Fetch Sunscription DB from RAN Function using RIC Request ID */
354 *ricSubscriptionInfo = fetchSubsInfoFromRicReqId(ricReqId, *ranFuncDb, ricSubscriptionNode);
355 if((*ricSubscriptionInfo) == NULLP)
363 /*******************************************************************
365 * @brief Sends E2 msg over SCTP
369 * Function : SendE2APMsg
371 * Functionality: Sends E2 msg over SCTP
373 * @params[in] Region region
375 * @return ROK - success
378 * ****************************************************************/
380 uint8_t SendE2APMsg(Region region, Pool pool, char *encBuf, int encBufSize)
384 if(ODU_GET_MSG_BUF(region, pool, &mBuf) == ROK)
386 if(ODU_ADD_POST_MSG_MULT((Data *)encBuf, encBufSize, mBuf) == ROK)
388 ODU_PRINT_MSG(mBuf, 0,0);
390 if(sctpSend(mBuf, E2_INTERFACE) != ROK)
392 DU_LOG("\nERROR --> E2AP : SCTP Send for E2 failed");
393 ODU_PUT_MSG_BUF(mBuf);
399 DU_LOG("\nERROR --> E2AP : ODU_ADD_POST_MSG_MULT failed");
400 ODU_PUT_MSG_BUF(mBuf);
403 ODU_PUT_MSG_BUF(mBuf);
407 DU_LOG("\nERROR --> E2AP : Failed to allocate memory");
414 /*******************************************************************
420 * Function : ResetE2Request
422 * Functionality: This function resets E2.
423 * As per ORAN WG3 E2GAP v3.0 Spec, section 5.5.3
424 * If E2 node initates reset procedure then:
425 * a. Send reset request to RIC
426 * b. Delete any pre-established RIC subscriptions
427 * c. Gracefully terminates any ongoing RIC services
428 * If RIC initiates reset procedure then :
429 * a. Delete any pre-established RIC subscriptions
430 * b. Gracefully terminates any ongoing RIC services
431 * c. Send reset response to RIC
434 * @return ROK - success
437 * ****************************************************************/
438 uint8_t ResetE2Request(E2ProcedureDirection dir, E2FailureCause resetCause)
440 /* Send Reset Request to RIC if DU detects any abnormal failure */
441 if(dir == E2_NODE_INITIATED)
443 if(BuildAndSendE2ResetRequest(resetCause) != ROK)
445 DU_LOG("\nERROR --> E2AP : BuildAndSendE2ResetRequest failed");
450 /* TODO when RIC subscription service model is implemented
451 Process following steps of resetting E2
452 1. Deletes any pre-established RIC subscriptions
453 2. Gracefully terminates any ongoing RIC services
456 /* Send Reset Response if RIC initiated Reset request is received at DU */
457 if(dir == RIC_INITIATED)
459 //BuildAndSendE2ResetResponse();
464 /*******************************************************************
466 * @brief Fill RIC Subscription datils in MAC Statistics Request
470 * Function : fillRicSubsInMacStatsReq
472 * Functionality: Fill RIC Subscription datils in MAC Statistics
475 * @params[in] MAC Statistics Request to be filled
476 * RIC Subscription Info
478 * @return ROK - success
481 * ****************************************************************/
482 uint8_t fillRicSubsInMacStatsReq(MacStatsReq *macStatsReq, RicSubscription* ricSubscriptionInfo)
484 uint8_t actionIdx = 0, grpIdx = 0, statsIdx = 0;
485 uint64_t subscriptionId = 0;
486 ActionInfo *actionDb = NULLP;
487 CmLList *actionNode = NULLP;
488 ActionDefFormat1 *format1Action = NULLP;
490 /* Generate subscription ID using RIC Request ID and RAN Function ID */
491 encodeSubscriptionId(&subscriptionId, ricSubscriptionInfo->ranFuncId, ricSubscriptionInfo->requestId);
493 macStatsReq->subscriptionId = subscriptionId;
494 CM_LLIST_FIRST_NODE(&ricSubscriptionInfo->actionSequence, actionNode);
497 actionDb = (ActionInfo*)(actionNode->node);
498 if(actionDb->action == CONFIG_ADD)
500 macStatsReq->statsGrpList[grpIdx].groupId = actionDb->actionId;
501 switch(actionDb->definition.formatType)
505 format1Action = &actionDb->definition.choice.format1;
506 macStatsReq->statsGrpList[grpIdx].periodicity = format1Action->granularityPeriod;
508 CmLList *node = NULLP;
509 MeasurementInfo *measInfo = NULLP;
511 /* Update DL PRB Usage for all stats group which requested for DL Total PRB Usage */
512 node = cmLListFirst(&format1Action->measurementInfoList);
515 measInfo = (MeasurementInfo *)(node->node);
516 switch(measInfo->measurementTypeId)
520 macStatsReq->statsGrpList[grpIdx].statsList[statsIdx++] = MAC_DL_TOTAL_PRB_USAGE;
525 macStatsReq->statsGrpList[grpIdx].statsList[statsIdx++] = MAC_UL_TOTAL_PRB_USAGE;
530 DU_LOG("\nERROR --> E2AP : Invalid measurement name");
536 macStatsReq->statsGrpList[grpIdx].numStats = statsIdx;
541 DU_LOG("\nERROR --> E2AP : fillRicSubsInMacStatsReq: Only Action Definition Format 1 supported");
545 if(macStatsReq->statsGrpList[grpIdx].numStats)
548 actionNode = actionNode->next;
551 macStatsReq->numStatsGroup = grpIdx;
552 if(macStatsReq->numStatsGroup)
559 /*******************************************************************
561 * @brief Rejects all actions received in a subscription request
565 * Function : duRejectAllStatsGroup
567 * Functionality: Rejects all actions received in a subscription
569 * a. Removing the subscription entry from RAN function
570 * b. Sending RIC Subscription Failure to RIC with appropriate
573 * @params[in] RAN Function DB
574 * Subscription entry in RAN Function subscription list
575 * Statistics Response from MAC
577 * @return ROK - success
580 * ****************************************************************/
581 uint8_t rejectAllStatsGroup(RanFunction *ranFuncDb, CmLList *ricSubscriptionNode, MacStatsRsp *statsRsp)
584 RicRequestId requestId;
585 E2FailureCause failureCause;
587 /* Delete subcription from RAN Function */
588 memcpy(&requestId, &((RicSubscription *)ricSubscriptionNode->node)->requestId, sizeof(RicRequestId));
589 cmLListDelFrm(&ranFuncDb->subscriptionList, ricSubscriptionNode);
590 deleteRicSubscriptionNode(ricSubscriptionNode);
591 ricSubscriptionNode = NULLP;
592 convertDuCauseToE2Cause(statsRsp->statsGrpRejectedList[0].cause, &failureCause);
594 /* Send RIC subscription failure to RIC */
595 ret = BuildAndSendRicSubscriptionFailure(requestId, ranFuncDb->id, failureCause);
599 /*******************************************************************
601 * @brief Process statistics response from MAC
605 * Function : e2ProcStatsRsp
607 * Functionality: Processes statistics configuration response
608 * from MAC. If configuration is succsessful, DUAPP starts
609 * reporting period timer for this subscription request
612 * @params[in] Statistics response received from MAC
614 * @return ROK - success
617 * ****************************************************************/
618 uint8_t e2ProcStatsRsp(MacStatsRsp *statsRsp)
621 uint8_t actionId = 0;
622 uint32_t reportingPeriod = 0;
623 RanFunction *ranFuncDb = NULLP;
624 CmLList *ricSubscriptionNode = NULLP;
625 CmLList *actionNode = NULLP;
626 RicSubscription *ricSubscriptionInfo = NULLP;
627 ActionInfo *actionInfoDb = NULLP;
628 PendingSubsRspInfo *pendingSubsRsp = NULLP;
630 /* Fetch RAN Function and Subscription DB using subscription Id received in statistics response */
631 if(fetchSubsInfoFromSubsId(statsRsp->subscriptionId, &ranFuncDb, &ricSubscriptionNode, &ricSubscriptionInfo) != ROK)
633 DU_LOG("\nERROR --> E2AP : DuProcMacStatsRsp: Failed to fetch subscriprtion details");
637 /* Fetch pre-stored statistics response info by DU APP */
638 for(idx=0; idx<ranFuncDb->numPendingSubsRsp; idx++)
640 if((ranFuncDb->pendingSubsRspInfo[idx].requestId.requestorId == ricSubscriptionInfo->requestId.requestorId) &&
641 (ricSubscriptionInfo->requestId.instanceId == ricSubscriptionInfo->requestId.instanceId))
643 pendingSubsRsp = &ranFuncDb->pendingSubsRspInfo[idx];
648 /* If no action is accepted
649 * a. Remove subcription entry from RAN Function
650 * b. Send RIC subscription failure */
651 if(statsRsp->numGrpAccepted == 0)
653 rejectAllStatsGroup(ranFuncDb, ricSubscriptionNode, statsRsp);
657 /* Once RIC subscription is successful, mark the config action as unknown */
658 ricSubscriptionInfo->action = CONFIG_UNKNOWN;
660 /* Start RIC Subscription reporting timer */
661 switch(ricSubscriptionInfo->eventTriggerDefinition.formatType)
665 reportingPeriod = ricSubscriptionInfo->eventTriggerDefinition.choice.format1.reportingPeriod;
667 /* Save the start time of reporting period */
668 storeReportStartTime(&ricSubscriptionInfo->eventTriggerDefinition.choice.format1.startTime);
673 DU_LOG("\nERROR --> E2AP : Invalid event trigger format of RIC subscription");
677 if(duChkTmr((PTR)ricSubscriptionInfo, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR) != true)
679 duStartTmr((PTR)ricSubscriptionInfo, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR, reportingPeriod);
683 DU_LOG("\nERROR --> E2AP : RIC Subscription reporting timer already running for RIC Subscription");
688 /* If even 1 action is accepted :
690 * For accepted groups:
691 * Mark subscribed-action's -> action = CONFIG_UNKNOWN
692 * Add to accepted-action-list of subscription response
694 for(idx=0; idx<statsRsp->numGrpAccepted; idx++)
696 actionInfoDb = NULLP;
698 actionId = statsRsp->statsGrpAcceptedList[idx];
699 actionInfoDb = fetchActionInfoFromActionId(actionId, ricSubscriptionInfo, &actionNode);
700 if(actionInfoDb && (actionInfoDb->action == CONFIG_ADD))
702 actionInfoDb->action = CONFIG_UNKNOWN;
703 pendingSubsRsp->acceptedActionList[pendingSubsRsp->numOfAcceptedActions++] = actionId;
707 /* For rejected groups:
708 * Remove entry from DU's RAN Function->subscription->actionList
709 * Add to rejected-action-list in subscription response
711 for(idx=0; idx<statsRsp->numGrpRejected; idx++)
713 actionInfoDb = NULLP;
714 actionId = statsRsp->statsGrpRejectedList[idx].groupId;
715 actionInfoDb = fetchActionInfoFromActionId(actionId, ricSubscriptionInfo, &actionNode);
716 if(actionInfoDb->actionId == actionId)
718 deleteActionSequence(actionNode);
719 pendingSubsRsp->rejectedActionList[pendingSubsRsp->numOfRejectedActions].id = actionId;
720 convertDuCauseToE2Cause(statsRsp->statsGrpRejectedList[idx].cause, \
721 &pendingSubsRsp->rejectedActionList[pendingSubsRsp->numOfRejectedActions].failureCause);
722 pendingSubsRsp->numOfRejectedActions++;
726 /* Send subscription response with accepted and rejected action lists to RIC */
727 BuildAndSendRicSubscriptionRsp(pendingSubsRsp);
729 memset(pendingSubsRsp, 0, sizeof(PendingSubsRspInfo));
733 /*******************************************************************
735 * @brief Extract and store statistics received from DU layers
739 * Function : e2ProcStatsInd
741 * Functionality: Extract statistics received from DU layers
742 * and store in respective RAN function's subscription's
745 * @params[in] Statistics Indication message received from MAC
746 * @return ROK-success
749 * ****************************************************************/
750 uint8_t e2ProcStatsInd(MacStatsInd *statsInd)
752 uint8_t statsIdx = 0;
753 RanFunction *ranFuncDb = NULLP;
754 CmLList *ricSubscriptionNode = NULLP;
755 CmLList *actionNode = NULLP;
756 RicSubscription *ricSubscriptionInfo = NULLP;
757 ActionInfo *actionInfo = NULLP;
758 ActionDefFormat1 *actionFormat = NULLP;
759 char e2MeasTypeName[STRING_SIZE_150_BYTES] = "";
760 MeasurementInfo *measInfo = NULLP;
761 CmLList *measInfoNode = NULLP;
762 double *measValue = NULLP;
763 CmLList *measValueNode = NULLP;
765 /* TODO : When stats indication is received
766 * DU APP searches for the message type in E2AP RIC subscription
767 * database and stores in the value in the list of subscribed measurements
769 * This will be implemented in next gerrit.
772 /* Fetch RAN Function and Subscription DB using subscription Id received
773 * in statistics response */
774 if(fetchSubsInfoFromSubsId(statsInd->subscriptionId, &ranFuncDb, &ricSubscriptionNode, &ricSubscriptionInfo) != ROK)
776 DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Failed to fetch subscriprtion details");
780 /* Fetch RIC subscription's action DB */
781 actionInfo = fetchActionInfoFromActionId(statsInd->groupId, ricSubscriptionInfo, &actionNode);
782 if(actionInfo == NULLP)
784 DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Failed to fetch action ID [%d]", statsInd->groupId);
788 /* Check Action format */
789 switch(actionInfo->definition.formatType)
793 actionFormat = &actionInfo->definition.choice.format1;
798 DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Action Format [%d] is not supported", \
799 actionInfo->definition.formatType);
804 /* Fetch each Measurement info from action info and store its reported value in DB */
805 for(statsIdx = 0; statsIdx < statsInd->numStats; statsIdx++)
807 memset(e2MeasTypeName, 0, STRING_SIZE_150_BYTES);
809 measInfoNode = NULLP;
811 /* Convert Measurement type from MAC-supported format to E2-supported format */
812 if(convertMacMeasTypeToE2MeasType(statsInd->measuredStatsList[statsIdx].type, e2MeasTypeName) != ROK)
814 DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Failed to convert measurement type from MAC-supported\
815 MAC-supported format to E2-supported format");
819 /* Fetch Measurement Info using E2-supported measurement type name */
820 measInfo = fetchMeasInfoFromMeasTypeName(e2MeasTypeName, &actionFormat->measurementInfoList, &measInfoNode);
821 if(measInfo == NULLP)
823 DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Measurement Type Name [%s] not found", e2MeasTypeName);
827 /* Store the measurement value in the measurement info DB fetched */
828 DU_ALLOC(measValue, sizeof(double));
831 DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Memory allocation failed at line [%d]", __LINE__);
834 *measValue = statsInd->measuredStatsList[statsIdx].value;
836 DU_ALLOC(measValueNode, sizeof(CmLList));
839 DU_LOG("\nERROR --> E2AP : extractStatsMeasurement: Memory allocation failed at line [%d]", __LINE__);
840 DU_FREE(measValue, sizeof(double));
843 measValueNode->node = (PTR) measValue;
844 cmLListAdd2Tail(&measInfo->measuredValue, measValueNode);
849 /*******************************************************************
851 * @brief Handle RIC Subscription reporting timer expry
855 * Function : E2apHdlRicSubsReportTmrExp
857 * Functionality: On expiry of RIC subscription reporting
858 * timer expiry, RIC indication is sent for all actions
859 * in RIC subscription
861 * @params[in] RIC subscription DB
864 * ****************************************************************/
865 void E2apHdlRicSubsReportTmrExp(RicSubscription *ricSubscription)
867 uint8_t actionIdx = 0;
868 uint32_t reportingPeriod = 0;
869 ActionInfo *action=NULLP;
870 CmLList *actionNode=NULLP;
872 CM_LLIST_FIRST_NODE(&ricSubscription->actionSequence, actionNode);
875 action = (ActionInfo*)actionNode->node;
876 BuildAndSendRicIndication(ricSubscription, action);
877 actionNode = actionNode->next;
880 /* Start RIC Subscription reporting timer again */
881 switch(ricSubscription->eventTriggerDefinition.formatType)
885 reportingPeriod = ricSubscription->eventTriggerDefinition.choice.format1.reportingPeriod;
886 /* Save the start time of reporting period */
887 storeReportStartTime(&ricSubscription->eventTriggerDefinition.choice.format1.startTime);
893 if(duChkTmr((PTR)ricSubscription, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR) != true)
895 duStartTmr((PTR)ricSubscription, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR, reportingPeriod);
899 DU_LOG("\nERROR --> E2AP : Failed in %s at line %d", __func__, __LINE__);
904 /******************************************************************
906 * @brief Search E2 node component with the help of action type
910 * Function : fetchE2NodeComponentInfo
912 * Functionality: Search E2 node component with the help of action type
917 * Pointer to E2 component node to be searched
920 * ****************************************************************/
922 E2NodeComponent *fetchE2NodeComponentInfo(InterfaceType interfaceType, uint64_t componentId, CmLList **e2ComponentNode)
924 E2NodeComponent *e2NodeComponentInfo=NULLP;
926 if(duCb.e2apDb.e2NodeComponentList.count)
928 CM_LLIST_FIRST_NODE(&duCb.e2apDb.e2NodeComponentList, *e2ComponentNode);
929 while(*e2ComponentNode)
931 e2NodeComponentInfo = (E2NodeComponent*)((*e2ComponentNode)->node);
932 if((e2NodeComponentInfo->interfaceType == interfaceType) && (e2NodeComponentInfo->componentId == componentId))
937 *e2ComponentNode = (*e2ComponentNode)->next;
938 e2NodeComponentInfo = NULLP;
941 return e2NodeComponentInfo;
944 /*******************************************************************
946 * @brief fill E2 node component rsp info
950 * Function : fillE2NodeComponentRspInfo
952 * Functionality: fill E2 Node Component rsp info
956 * Component action type
957 * Size of buffer which needs to be store
958 * buffer string which needs to be store
959 * @return ROK - success
962 * ****************************************************************/
964 uint8_t fillE2NodeComponentRspInfo(InterfaceType interfaceType, uint64_t componentId, uint8_t action, uint8_t bufSize, char *bufString)
966 E2NodeConfig *configInfo=NULLP;
967 E2NodeComponent *e2NodeComponentInfo= NULLP;
968 CmLList *node = NULLP;
970 e2NodeComponentInfo = fetchE2NodeComponentInfo(interfaceType, componentId, &node);
971 if(!e2NodeComponentInfo)
973 DU_LOG("\nERROR --> E2AP : Unable to find the node");
979 case E2_NODE_COMPONENT_ADD:
981 configInfo = e2NodeComponentInfo->addConfiguration;
984 case E2_NODE_COMPONENT_UPDATE:
986 configInfo = e2NodeComponentInfo->updateConfiguration;
991 DU_LOG("\nERROR --> E2AP : Invalid action %d received",action);
996 if(configInfo->componentRequestPart== NULLP)
998 DU_LOG("\nERROR --> E2AP : E2 node Component request part is not present");
1002 configInfo->rspBufSize = bufSize;
1003 DU_ALLOC(configInfo->componentResponsePart, bufSize);
1004 if(configInfo->componentResponsePart == NULLP)
1006 DU_LOG("\nERROR --> E2AP : Memory allocation failed to store the encoding of rsp");
1009 memcpy(configInfo->componentResponsePart, bufString, configInfo->rspBufSize);
1013 /*******************************************************************
1015 * @brief add E2 node component req info
1019 * Function : addE2NodeComponent
1021 * Functionality: add E2 node component req info
1025 * Component action type
1026 * Size of buffer which needs to be store
1027 * buffer string which needs to be store
1028 * @return ROK - success
1031 ******************************************************************/
1033 uint8_t addE2NodeComponent(InterfaceType interfaceType, uint64_t componentId, uint8_t bufSize, char *bufString)
1035 E2NodeComponent *e2NodeComponentInfo= NULLP;
1036 CmLList *node = NULLP;
1038 DU_ALLOC(e2NodeComponentInfo, sizeof(E2NodeComponent));
1039 if(!e2NodeComponentInfo)
1041 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
1044 e2NodeComponentInfo->interfaceType =interfaceType;
1045 e2NodeComponentInfo->componentId=componentId;
1047 DU_ALLOC(e2NodeComponentInfo->addConfiguration, sizeof(E2NodeConfig));
1048 if(!e2NodeComponentInfo->addConfiguration)
1050 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
1054 e2NodeComponentInfo->addConfiguration->reqBufSize = bufSize;
1056 DU_ALLOC(e2NodeComponentInfo->addConfiguration->componentRequestPart, bufSize);
1057 if(e2NodeComponentInfo->addConfiguration->componentRequestPart == NULLP)
1059 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
1060 DU_FREE(e2NodeComponentInfo, sizeof(E2NodeComponent));
1063 memcpy(e2NodeComponentInfo->addConfiguration->componentRequestPart, bufString,\
1064 e2NodeComponentInfo->addConfiguration->reqBufSize);
1066 DU_ALLOC(node, sizeof(CmLList));
1069 node->node = (PTR) e2NodeComponentInfo;
1070 cmLListAdd2Tail(&duCb.e2apDb.e2NodeComponentList, node);
1074 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
1075 DU_FREE(e2NodeComponentInfo->addConfiguration->componentRequestPart, bufSize);
1076 DU_FREE(e2NodeComponentInfo->addConfiguration, sizeof(E2NodeConfig));
1077 DU_FREE(e2NodeComponentInfo, sizeof(E2NodeComponent));
1083 /*******************************************************************
1085 * @brief update E2 node component req info
1089 * Function : updateE2NodeComponent
1091 * Functionality: update E2 node component req info
1095 * Size of buffer which needs to be store
1096 * buffer string which needs to be store
1097 * @return ROK - success
1100 ******************************************************************/
1102 uint8_t updateE2NodeComponent(InterfaceType interfaceType, uint64_t componentId, uint8_t bufSize, char *bufString)
1104 E2NodeComponent *e2NodeComponentInfo= NULLP;
1105 CmLList *node = NULLP;
1107 e2NodeComponentInfo = fetchE2NodeComponentInfo(interfaceType, componentId, &node);
1108 if(!e2NodeComponentInfo)
1110 DU_LOG("\nERROR --> E2AP : Received null information in %s",__func__);
1114 DU_ALLOC(e2NodeComponentInfo->updateConfiguration, sizeof(E2NodeConfig));
1115 if(!e2NodeComponentInfo->updateConfiguration)
1117 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
1121 e2NodeComponentInfo->updateConfiguration->reqBufSize = bufSize;
1123 DU_ALLOC(e2NodeComponentInfo->updateConfiguration->componentRequestPart, bufSize);
1124 if(e2NodeComponentInfo->updateConfiguration->componentRequestPart == NULLP)
1126 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
1127 DU_FREE(e2NodeComponentInfo->updateConfiguration, sizeof(E2NodeConfig));
1131 memcpy(e2NodeComponentInfo->updateConfiguration->componentRequestPart, bufString,\
1132 e2NodeComponentInfo->updateConfiguration->reqBufSize);
1137 /*******************************************************************
1139 * @brief delete E2 node component req info
1143 * Function : deleteE2NodeComponent
1145 * Functionality: delete E2 node component req info
1149 * @return ROK - success
1152 ******************************************************************/
1154 uint8_t deleteE2NodeComponent(InterfaceType interfaceType, uint64_t componentId)
1156 E2NodeComponent *e2NodeComponentInfo= NULLP;
1157 CmLList *node = NULLP;
1159 e2NodeComponentInfo = fetchE2NodeComponentInfo(interfaceType, componentId, &node);
1160 if(!e2NodeComponentInfo)
1162 DU_LOG("\nERROR --> E2AP : Received null information in %s",__func__);
1166 e2NodeComponentInfo->deleteConfiguration = true;
1170 /*******************************************************************
1172 * @brief fill E2 node component req info
1176 * Function : fillE2NodeComponentReqInfo
1178 * Functionality: fill E2 node component req info
1182 * Component action type
1183 * Size of buffer which needs to be store
1184 * buffer string which needs to be store
1185 * @return ROK - success
1188 ******************************************************************/
1190 uint8_t fillE2NodeComponentReqInfo(InterfaceType interfaceType, uint64_t componentId, uint8_t action, uint8_t bufSize, char *bufString)
1194 case E2_NODE_COMPONENT_ADD:
1196 if(addE2NodeComponent(interfaceType, componentId, bufSize, bufString) != ROK)
1198 DU_LOG("\nERROR --> E2AP : Failed to add e2 node component");
1203 case E2_NODE_COMPONENT_UPDATE:
1205 if(updateE2NodeComponent(interfaceType, componentId, bufSize, bufString) != ROK)
1207 DU_LOG("\nERROR --> E2AP : Failed to update e2 node component");
1212 case E2_NODE_COMPONENT_DEL:
1214 if(deleteE2NodeComponent(interfaceType, componentId) != ROK)
1216 DU_LOG("\nERROR --> E2AP : Failed to delete e2 node component");
1223 DU_LOG("\nERROR --> E2AP : Invalid action %d received",action);
1231 /******************************************************************
1233 * @brief Delete measured Value list
1237 * Function : deleteMeasuredValueList
1239 * Functionality: Delete measured Value list
1241 * @params[in] List of measured Value
1245 * ****************************************************************/
1246 void deleteMeasuredValueList(CmLListCp *measuredValueList)
1248 CmLList *measValNode = NULLP;
1250 CM_LLIST_FIRST_NODE(measuredValueList, measValNode);
1254 cmLListDelFrm(measuredValueList, measValNode);
1255 DU_FREE(measValNode->node, sizeof(double));
1256 DU_FREE(measValNode, sizeof(CmLList));
1257 CM_LLIST_FIRST_NODE(measuredValueList, measValNode);
1261 /******************************************************************
1263 * @brief Delete Measurement Info List
1267 * Function : deleteMeasurementInfoList
1269 * Functionality: Delete Measurement Info List
1271 * @params[in] List of Measurement Info List
1275 * ****************************************************************/
1276 void deleteMeasurementInfoList(CmLListCp *measInfoList)
1278 CmLList *measInfoNode = NULLP;
1279 MeasurementInfo *measInfo = NULLP;
1281 CM_LLIST_FIRST_NODE(measInfoList, measInfoNode);
1284 measInfo = (MeasurementInfo *)measInfoNode->node;
1285 cmLListDelFrm(measInfoList, measInfoNode);
1286 deleteMeasuredValueList(&measInfo->measuredValue);
1287 DU_FREE(measInfo, sizeof(MeasurementInfo));
1288 DU_FREE(measInfoNode, sizeof(CmLList));
1289 CM_LLIST_FIRST_NODE(measInfoList, measInfoNode);
1293 /******************************************************************
1295 * @brief Delete Ric subscription action
1299 * Function : deleteActionSequence
1301 * Functionality: Delete Ric subscription action
1303 * @params[in] Action info
1307 * ****************************************************************/
1308 void deleteActionSequence(CmLList *actionNode)
1310 ActionInfo *action = NULLP;
1311 ActionDefinition *definition=NULLP;
1315 action = (ActionInfo*)actionNode->node;
1316 definition= &action->definition;
1318 switch(definition->formatType)
1322 deleteMeasurementInfoList(&definition->choice.format1.measurementInfoList);
1332 DU_LOG("\nERROR --> E2AP : Format %d does not supported", definition->formatType);
1336 memset(action, 0, sizeof(ActionInfo));
1337 DU_FREE(actionNode->node, sizeof(ActionInfo));
1338 DU_FREE(actionNode, sizeof(CmLList));
1342 /******************************************************************
1344 * @brief Delete Ric subscription action list
1348 * Function : deleteActionSequenceList
1350 * Functionality: Delete Ric subscription action list
1352 * @params[in] Action info list
1356 * ****************************************************************/
1357 void deleteActionSequenceList(CmLListCp *actionList)
1359 CmLList *actionNode=NULLP;
1361 CM_LLIST_FIRST_NODE(actionList, actionNode);
1364 cmLListDelFrm(actionList, actionNode);
1365 deleteActionSequence(actionNode);
1366 CM_LLIST_FIRST_NODE(actionList, actionNode);
1370 /******************************************************************
1372 * @brief Delete Ric subscription node
1376 * Function : deleteRicSubscriptionNode
1378 * Functionality: Delete Ric subscription node
1380 * @params[in] Ric subscription info
1384 * ****************************************************************/
1385 void deleteRicSubscriptionNode(CmLList *subscriptionNode)
1387 RicSubscription *ricSubscriptionInfo = NULLP;
1389 ricSubscriptionInfo = (RicSubscription*)subscriptionNode->node;
1391 deleteActionSequenceList(&ricSubscriptionInfo->actionSequence);
1392 if(duChkTmr((PTR)ricSubscriptionInfo, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR) == TRUE)
1394 duStopTmr((PTR)ricSubscriptionInfo, EVENT_RIC_SUBSCRIPTION_REPORTING_TMR);
1397 memset(ricSubscriptionInfo, 0, sizeof(RicSubscription));
1398 DU_FREE(subscriptionNode->node, sizeof(RicSubscription));
1399 DU_FREE(subscriptionNode, sizeof(CmLList));
1402 /******************************************************************
1404 * @brief Delete ric subscription list from the database
1408 * Function : deleteRicSubscriptionList
1410 * Functionality: Delete ric subscription list
1413 * Subscription List to be deleted
1417 * ****************************************************************/
1418 void deleteRicSubscriptionList(CmLListCp *subscriptionList)
1420 CmLList *subscriptionNode=NULLP;
1422 CM_LLIST_FIRST_NODE(subscriptionList, subscriptionNode);
1423 while(subscriptionNode)
1425 /* TODO - Remove subscription information from MAC and SCH as well */
1426 cmLListDelFrm(subscriptionList, subscriptionNode);
1427 deleteRicSubscriptionNode(subscriptionNode);
1428 CM_LLIST_FIRST_NODE(subscriptionList, subscriptionNode);
1432 /*******************************************************************
1434 * @brief Find all RIC subscriptions to be deleted in all RAN
1439 * Function : fetchRicSubsToBeDeleted
1441 * Functionality: Find all RIC subscriptions to be deleted in all
1442 * RAN functions and store in a temporary list
1444 * @parameter Temporary list to store subscriptions to be deleted
1447 ******************************************************************/
1448 void fetchRicSubsToBeDeleted(CmLListCp *ricSubsToBeDelList)
1450 uint16_t ranFuncIdx = 0;
1451 CmLList *subsNode = NULLP;
1452 CmLList *subsToDelNode = NULLP;
1454 for(ranFuncIdx = 0; ranFuncIdx < MAX_RAN_FUNCTION; ranFuncIdx++)
1456 if(duCb.e2apDb.ranFunction[ranFuncIdx].id > 0)
1458 CM_LLIST_FIRST_NODE(&duCb.e2apDb.ranFunction[ranFuncIdx].subscriptionList, subsNode);
1461 if(((RicSubscription *)subsNode->node)->action == CONFIG_DEL)
1463 DU_ALLOC(subsToDelNode, sizeof(CmLList));
1466 DU_LOG("\nERROR --> E2AP : %s: Memory allocation failure at %d", __func__, __LINE__);
1469 subsToDelNode->node = subsNode->node;
1470 cmLListAdd2Tail(ricSubsToBeDelList, subsToDelNode);
1472 subsToDelNode = NULLP;
1473 subsNode = subsNode->next;
1479 /******************************************************************
1481 * @brief Delete e2 node information from the database
1485 * Function : removeE2NodeInformation
1487 * Functionality: Delete e2 node information from the database
1493 ******************************************************************/
1494 void removeE2NodeInformation()
1496 uint16_t ranFuncIdx = 0;
1498 DU_LOG("\nINFO --> E2AP : Deleting all the E2 node configuration");
1499 for(ranFuncIdx=0; ranFuncIdx<MAX_RAN_FUNCTION; ranFuncIdx++)
1501 if(duCb.e2apDb.ranFunction[ranFuncIdx].id >0)
1503 deleteRicSubscriptionList(&(duCb.e2apDb.ranFunction[ranFuncIdx].subscriptionList));
1504 memset(&(duCb.e2apDb.ranFunction[ranFuncIdx].pendingSubsRspInfo), 0, MAX_PENDING_SUBSCRIPTION_RSP*sizeof(PendingSubsRspInfo));
1507 memset(&duCb.e2apDb.ricId, 0, sizeof(GlobalRicId));
1508 duCb.e2apDb.numOfTNLAssoc = 0;
1509 memset(&duCb.e2apDb.tnlAssoc, 0, MAX_TNL_ASSOCIATION*sizeof(TNLAssociation));
1510 memset(&ricParams, 0, sizeof(DuSctpDestCb));
1513 /*******************************************************************
1515 * @brief Extract statistics received from DU layers and delete
1516 * Ric subscription info
1520 * Function :e2ProcStatsDeleteRsp
1522 * Functionality: Extract statistics received from DU layers
1523 * and delete ric subscription iformation form db
1525 * @params[in] Statistics delete rsp from MAC
1526 * @return ROK-success
1529 * ****************************************************************/
1530 uint8_t e2ProcStatsDeleteRsp(MacStatsDeleteRsp *statsDeleteRsp)
1532 RicRequestId requestId;
1534 RanFunction *ranFuncDb = NULLP;
1535 CmLList *ricSubscriptionNode = NULLP;
1536 RicSubscription *ricSubscriptionInfo = NULLP;
1537 E2FailureCause failureCause;
1539 /* Fetch RAN Function and Subscription DB using subscription Id received
1540 * in statistics delete response */
1541 if(fetchSubsInfoFromSubsId(statsDeleteRsp->subscriptionId, &ranFuncDb, &ricSubscriptionNode, &ricSubscriptionInfo) != ROK)
1543 DU_LOG("\nERROR --> E2AP : e2ProcStatsDeleteRsp: Failed to fetch subscriprtion details");
1546 ranFuncId = ricSubscriptionInfo->ranFuncId;
1547 memcpy(&requestId, &ricSubscriptionInfo->requestId, sizeof(RicRequestId));
1549 deleteRicSubscriptionNode(ricSubscriptionNode);
1551 if(statsDeleteRsp->subsDelRsp == MAC_DU_APP_RSP_NOK)
1553 if(statsDeleteRsp->subsDelCause == STATS_ID_NOT_FOUND)
1555 failureCause.causeType =E2_RIC_REQUEST;
1556 failureCause.cause = E2_REQUEST_INFORMATION_UNAVAILABLE;
1560 failureCause.causeType = E2_MISCELLANEOUS;
1561 failureCause.cause = E2_MISCELLANEOUS_CAUSE_UNSPECIFIED;
1564 if(BuildAndSendRicSubscriptionDeleteFailure(ranFuncId, requestId, failureCause) != ROK)
1566 DU_LOG("\nERROR --> E2AP : e2ProcStatsDeleteRsp: failed to build and send ric subs delete failure");
1572 if(BuildAndSendRicSubscriptionDeleteResponse(ranFuncId, requestId) != ROK)
1574 DU_LOG("\nERROR --> E2AP : e2ProcStatsDeleteRsp: failed to build and send ric subs delete rsp");
1582 /*******************************************************************
1584 * @brief Fill RIC Subscription datils in MAC Statistics
1585 * ModificationRequest
1589 * Function : fillRicSubsInMacStatsModificationReq
1591 * Functionality: Fill RIC Subscription datils in MAC
1592 * Modification Statistics Request
1593 * [Step -1] Generate subscription ID using RIC Request ID and
1595 * [Step -2] Check all the action staus of each action present
1596 * in the ric subscription. If action is CONFIG_MOD then fill
1597 * the information in stats group list.
1598 * [Step -3] Fill group related information in stats modification
1599 * req's in stats group list
1600 * [Step -4] fill measurement information in stats group list
1601 * [Step -5] If the number of stats which needs to modify is
1602 * greater then zero then return ROK else return RFAILED
1604 * @params[in] MAC Statistics Modification Request to be filled
1605 * RIC Subscription Info
1607 * @return ROK - success
1610 * ****************************************************************/
1611 uint8_t fillRicSubsInMacStatsModificationReq(MacStatsModificationReq *macStatsModificationReq, RicSubscription* ricSubscriptionInfo)
1614 uint8_t statsModifyReqIdx = 0;
1615 uint64_t subscriptionId = 0;
1616 CmLList *node = NULLP;
1617 ActionInfo *actionDb = NULLP;
1618 CmLList *actionNode = NULLP;
1619 MeasurementInfo *measInfo = NULLP;
1620 ActionDefFormat1 *format1Action = NULLP;
1623 encodeSubscriptionId(&subscriptionId, ricSubscriptionInfo->ranFuncId, ricSubscriptionInfo->requestId);
1625 macStatsModificationReq->subscriptionId = subscriptionId;
1626 CM_LLIST_FIRST_NODE(&ricSubscriptionInfo->actionSequence, actionNode);
1629 actionDb = (ActionInfo*)(actionNode->node);
1631 if(actionDb->action == CONFIG_MOD)
1634 macStatsModificationReq->statsGrpList[grpIdx].groupId = actionDb->actionId;
1635 switch(actionDb->definition.formatType)
1639 format1Action = &actionDb->definition.choice.format1;
1640 macStatsModificationReq->statsGrpList[grpIdx].periodicity = format1Action->granularityPeriod;
1642 statsModifyReqIdx = 0;
1643 node = cmLListFirst(&format1Action->measurementInfoList);
1647 measInfo = (MeasurementInfo *)(node->node);
1648 switch(measInfo->measurementTypeId)
1652 macStatsModificationReq->statsGrpList[grpIdx].statsList[statsModifyReqIdx++] = MAC_DL_TOTAL_PRB_USAGE;
1657 macStatsModificationReq->statsGrpList[grpIdx].statsList[statsModifyReqIdx++] = MAC_UL_TOTAL_PRB_USAGE;
1662 DU_LOG("\nERROR --> E2AP : Invalid measurement name");
1668 macStatsModificationReq->statsGrpList[grpIdx].numStats = statsModifyReqIdx;
1673 DU_LOG("\nERROR --> E2AP : fillRicSubsInMacStatsModificationReq: Only Action Definition Format 1 supported");
1677 if(macStatsModificationReq->statsGrpList[grpIdx].numStats)
1680 actionNode = actionNode->next;
1684 macStatsModificationReq->numStatsGroup = grpIdx;
1685 if(macStatsModificationReq->numStatsGroup)
1692 /**********************************************************************
1694 **********************************************************************/