X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=src%2F5gnrsch%2Fsch.c;h=8279bf6c6ac158b655b88159427ba9117dee0382;hb=2e3617064e27b8d7bb5ba74319f8c1c99491b8dd;hp=8e90431a2101d9f46c39ec18c778c6216cec03ac;hpb=a14bf79bbc001990f96e01ada0dd291bcc9ddcad;p=o-du%2Fl2.git diff --git a/src/5gnrsch/sch.c b/src/5gnrsch/sch.c index 8e90431a2..8279bf6c6 100644 --- a/src/5gnrsch/sch.c +++ b/src/5gnrsch/sch.c @@ -131,6 +131,11 @@ uint8_t SchInstCfg(RgCfg *cfg, Inst dInst) return (LCM_REASON_MEM_NOAVAIL); } + /* Initialize statistics related configurations */ + memset(&schCb[inst].statistics, 0, sizeof(SchStatistics)); + cmLListInit(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList); + cmLListInit(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList); + /* Set Config done in TskInit */ schCb[inst].schInit.cfgDone = TRUE; DU_LOG("\nINFO --> SCH : Scheduler gen config done"); @@ -590,7 +595,7 @@ uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchC uint8_t mValue = 0; uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */ uint8_t slotIndex = 0; - uint8_t FreqDomainResource[FREQ_DOM_RSRC_SIZE] = {0}; + uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0}; uint16_t tbSize = 0; uint8_t ssbIdx = 0; PdcchCfg *pdcch; @@ -650,8 +655,8 @@ uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchC pdcch->coresetCfg.durationSymbols = numSymbols; /* Fill Bitmap for PRBs in coreset */ - fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), FreqDomainResource); - covertFreqDomRsrcMapToIAPIFormat(FreqDomainResource, pdcch->coresetCfg.freqDomainResource); + fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), freqDomainResource); + memcpy(pdcch->coresetCfg.freqDomainResource, freqDomainResource, FREQ_DOM_RSRC_SIZE); pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */ pdcch->coresetCfg.regBundleSize = 6; /* spec-38.211 sec 7.3.2.2 */ @@ -660,21 +665,21 @@ uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchC pdcch->coresetCfg.shiftIndex = pci; pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */ pdcch->numDlDci = 1; - pdcch->dci.rnti = SI_RNTI; - pdcch->dci.scramblingId = pci; - pdcch->dci.scramblingRnti = 0; - pdcch->dci.cceIndex = 0; - pdcch->dci.aggregLevel = 4; - pdcch->dci.beamPdcchInfo.numPrgs = 1; - pdcch->dci.beamPdcchInfo.prgSize = 1; - pdcch->dci.beamPdcchInfo.digBfInterfaces = 0; - pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0; - pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0; - pdcch->dci.txPdcchPower.beta_pdcch_1_0= 0; - pdcch->dci.txPdcchPower.powerControlOffsetSS = 0; + pdcch->dci[0].rnti = SI_RNTI; + pdcch->dci[0].scramblingId = pci; + pdcch->dci[0].scramblingRnti = 0; + pdcch->dci[0].cceIndex = 0; + pdcch->dci[0].aggregLevel = 4; + pdcch->dci[0].beamPdcchInfo.numPrgs = 1; + pdcch->dci[0].beamPdcchInfo.prgSize = 1; + pdcch->dci[0].beamPdcchInfo.digBfInterfaces = 0; + pdcch->dci[0].beamPdcchInfo.prg[0].pmIdx = 0; + pdcch->dci[0].beamPdcchInfo.prg[0].beamIdx[0] = 0; + pdcch->dci[0].txPdcchPower.beta_pdcch_1_0= 0; + pdcch->dci[0].txPdcchPower.powerControlOffsetSS = 0; /* Storing pdschCfg pointer here. Required to access pdsch config while fillig up pdcch pdu */ - pdsch = &pdcch->dci.pdschCfg; + pdsch = &pdcch->dci[0].pdschCfg; /* fill the PDSCH PDU */ uint8_t cwCount = 0; @@ -777,9 +782,8 @@ uint8_t SchProcCellCfgReq(Pst *pst, SchCellCfg *schCellCfg) offset = coresetIdxTable[coreset0Idx][3]; fillCoresetFeqDomAllocMap(((cellCb->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA - offset)/6), \ (numRbs/6), freqDomainResource); - covertFreqDomRsrcMapToIAPIFormat(freqDomainResource, \ - cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc); - + memcpy(cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc,\ + freqDomainResource,FREQ_DOM_RSRC_SIZE); /* Fill K0 - K1 table for common cfg*/ BuildK0K1Table(cellCb, &cellCb->k0K1InfoTbl, true, cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon, pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl); @@ -924,13 +928,13 @@ void deleteSchCellCb(SchCellCb *cellCb) for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++) { - if(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai) + if(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai) { - for(sliceIdx=0; sliceIdxcellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++) + for(sliceIdx=0; sliceIdxcellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++) { - SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai)); + SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai)); } - SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport*sizeof(Snssai*)); + SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices*sizeof(Snssai*)); } } @@ -1293,7 +1297,7 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \ if(ssbOccasion && sib1Occasion) { broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; - broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1; + broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1; } else if(ssbOccasion) { @@ -1302,8 +1306,8 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \ } else if(sib1Occasion) { - broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.startPrb; - broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1; + broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb; + broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1; } /* Iterate through all free PRB blocks */ @@ -1383,7 +1387,7 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \ } /* Update statistics of PRB usage if stats calculation is enabled */ - if(schCb[cell->instIdx].statistics.dlTotalPrbUsage) + if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count) prbAlloc->numPrbAlloc += numPrb; /* Update the remaining number for free PRBs */ @@ -1520,7 +1524,7 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \ } /* Update statistics of PRB usage if stats calculation is enabled */ - if(schCb[cell->instIdx].statistics.ulTotalPrbUsage) + if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count) prbAlloc->numPrbAlloc += numPrb; /* Update the remaining number for free PRBs */ @@ -1579,7 +1583,7 @@ uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_ { reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \ - cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1; + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1; } else if(ssbOccasion) { @@ -1588,8 +1592,8 @@ uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_ } else if(sib1Occasion) { - reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.startPrb; - reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1; + reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb; + reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1; } else { @@ -1761,10 +1765,10 @@ uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, /* Here comparing the slice cfg request with the slice stored in cellCfg */ for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++) { - for(sliceIdx = 0; sliceIdxcellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++) + for(sliceIdx = 0; sliceIdxcellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++) { /* If we find the SliceCfgReq's SNSSAI in CellCb's SNSSAI DB, we mark this slice as configured and add it to Sch's DB. */ - if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai))) + if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai))) { if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK) { @@ -2516,29 +2520,29 @@ uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd) * RFAILED - failure * * ****************************************************************/ -uint8_t SchSendStatsRspToMac(Inst inst, SchMacRsp result, CauseOfResult cause) +uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp) { Pst rspPst; uint8_t ret = ROK; - SchStatsRsp *statsRsp; + SchStatsRsp *schStatsRsp; DU_LOG("\nINFO --> SCH : Filling statistics response"); - SCH_ALLOC(statsRsp, sizeof(SchStatsRsp)); - if(statsRsp == NULLP) + SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp)); + if(schStatsRsp == NULLP) { DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsRspToMac()"); return RFAILED; } + + memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp)); memset(statsRsp, 0, sizeof(SchStatsRsp)); - statsRsp->rsp = result; - statsRsp->cause = cause; /* Filling response post */ memset(&rspPst, 0, sizeof(Pst)); FILL_PST_SCH_TO_MAC(rspPst, inst); rspPst.event = EVENT_STATISTICS_RSP_TO_MAC; - ret = MacMessageRouter(&rspPst, (void *)statsRsp); + ret = MacMessageRouter(&rspPst, (void *)schStatsRsp); if(ret == RFAILED) { DU_LOG("\nERROR --> SCH : SchSendStatsRspToMac(): Failed to send Statistics Response"); @@ -2549,147 +2553,1024 @@ uint8_t SchSendStatsRspToMac(Inst inst, SchMacRsp result, CauseOfResult cause) /******************************************************************* * - * @brief Processes Statistics Request from MAC + * @brief Rejects all statistics group requested by MAC * * @details * - * Function : SchProcStatsReq + * Function : SchRejectAllStats * - * Functionality: - * Processes Statistics Request from MAC + * Functionality: Add all statistics group received in statistics + * request from MAC, to Reject-Stats-Group-List in statistics + * response to MAC * - * @params[in] + * @params[in] Statistics request from MAC + * Cause of rejection * @return ROK - success * RFAILED - failure * * ****************************************************************/ -uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq) +uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause) { - uint8_t idx; - Inst inst = pst->dstInst - SCH_INST_START; - SchMacRsp rsp = RSP_OK; - CauseOfResult cause = SUCCESSFUL; - bool isDlTotlPrbUseCfgd = false, isUlTotlPrbUseCfgd = false; + uint8_t grpIdx = 0; + SchStatsRsp schStatsRsp; - DU_LOG("\nINFO --> SCH : Received Statistics Request from MAC"); + memset(&schStatsRsp, 0, sizeof(SchStatsRsp)); + + /* Copying all stats group from stats request to stats response */ + schStatsRsp.subscriptionId = schStatsReq->subscriptionId; + for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++) + { + schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId; + schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause; + } + schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup; + + return SchSendStatsRspToMac(&schStatsRsp); +} + +/******************************************************************* + * + * @brief Add active KPI pointers to KPI-Active-List + * + * @details + * + * Function : schAddToKpiActiveList + * + * Functionality: For each active statistics group for which timer + * is running, add its KPI pointer to KPI-Active-List. + * Use case : + * When it is needed to update a KPI parameters, we need not + * traverse all statistics group and all KPIs within a group + * to get the specific KPI pointer to be updated. + * Instead, we can traverse through KPI-Active-List and update + * all entries in this list. + * + * @params[in] Pointer to the prb usage info link list + * Pointer to the stats ccnfig which we need to add + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo) +{ + CmLList *node = NULLP; - for(idx=0; idx < statsReq->numStats; idx++) + SCH_ALLOC(node, sizeof(CmLList)); + if(node) { - switch(statsReq->statsList[idx].type) + 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++) { - case SCH_DL_TOTAL_PRB_USAGE: - { - /* Check if duplicate configuration */ - if(schCb[inst].statistics.dlTotalPrbUsage) + /* Step 2.1 */ + switch(grpInfo->statsList[reqMeasIdx]) + { + case SCH_DL_TOTAL_PRB_USAGE: { - DU_LOG("\nERROR --> SCH : SCH_DL_TOTAL_PRB_USAGE stats already configured"); - rsp = RSP_NOK; - cause = DUPLICATE_ENTRY; + SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage)); + if(!grpInfoDb->kpiStats.dlTotalPrbUsage) + { + DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__); + measTypeInvalid = true; + cause = RESOURCE_UNAVAILABLE; + break; + } + break; } - /* Allocate memory */ - SCH_ALLOC(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage)); - if(!schCb[inst].statistics.dlTotalPrbUsage) + case SCH_UL_TOTAL_PRB_USAGE: { - DU_LOG("\nERROR --> SCH : Memory allocation failed for dlTotalPrbUsage in \ - SchProcStatsReq()"); - rsp = RSP_NOK; - cause = RESOURCE_UNAVAILABLE; + SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage)); + if(!grpInfoDb->kpiStats.ulTotalPrbUsage) + { + DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__); + measTypeInvalid = true; + cause = RESOURCE_UNAVAILABLE; + break; + } break; } - /* Initialize */ - memset(schCb[inst].statistics.dlTotalPrbUsage, 0, sizeof(TotalPrbUsage)); - - /* Configure */ - schCb[inst].statistics.dlTotalPrbUsage->schInst = inst; - schCb[inst].statistics.dlTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity; - cmInitTimers(&(schCb[inst].statistics.dlTotalPrbUsage->periodTimer), 1); + default: + { + DU_LOG("\nERROR --> SCH : SchProcStatsReq: Invalid measurement type [%d]", \ + grpInfo->statsList[reqMeasIdx]); + measTypeInvalid = true; + cause = PARAM_INVALID; + break; + } + } - /* Start timer */ - schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), \ - EVENT_DL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.dlTotalPrbUsage->periodicity); + if(measTypeInvalid) + { + ret =RFAILED; + break; + } + } - isDlTotlPrbUseCfgd = true; + while(measTypeInvalid==false) + { + if(grpInfoDb->kpiStats.dlTotalPrbUsage) + { + /* Step 2.2 */ + if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR)grpInfoDb->kpiStats.dlTotalPrbUsage)!=ROK) + { + DU_LOG("\nERROR --> E2AP : KPI addition failed in %s at %d",__func__,__LINE__); + cause = RESOURCE_UNAVAILABLE; + ret =RFAILED; break; } + } - case SCH_UL_TOTAL_PRB_USAGE: + if(grpInfoDb->kpiStats.ulTotalPrbUsage) + { + /* Step 2.2 */ + if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK) { - /* Check if duplicate configuration */ - if(schCb[inst].statistics.ulTotalPrbUsage) - { - DU_LOG("\nERROR --> SCH : SCH_UL_TOTAL_PRB_USAGE stats already configured"); - rsp = RSP_NOK; - cause = DUPLICATE_ENTRY; - } + DU_LOG("\nERROR --> E2AP : KPI addition failed in %s at %d",__func__,__LINE__); + cause = RESOURCE_UNAVAILABLE; + ret =RFAILED; + break; + } + } - /* Allocate memory */ - SCH_ALLOC(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage)); - if(!schCb[inst].statistics.ulTotalPrbUsage) - { - DU_LOG("\nERROR --> SCH : Memory allocation failed for ulTotalPrbUsage in \ - SchProcStatsReq()"); - rsp = RSP_NOK; - cause = RESOURCE_UNAVAILABLE; - break; - } + /* Step 2.3 */ + grpInfoDb->schInst = inst; + grpInfoDb->groupId = grpInfo->groupId; + grpInfoDb->periodicity = grpInfo->periodicity; + grpInfoDb->subscriptionId = subscriptionId; - /* Initialize */ - memset(schCb[inst].statistics.ulTotalPrbUsage, 0, sizeof(TotalPrbUsage)); + /* Step 2.4 */ + cmInitTimers(&(grpInfoDb->periodTimer), 1); + schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity); - /* Configure */ - schCb[inst].statistics.ulTotalPrbUsage->schInst = inst; - schCb[inst].statistics.ulTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity; - cmInitTimers(&(schCb[inst].statistics.ulTotalPrbUsage->periodTimer), 1); + /* 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; + } + } + } - /* Start timer */ - schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), \ - EVENT_UL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.ulTotalPrbUsage->periodicity); + if(ret != ROK) + { + /* Step 3 */ + if(grpInfoDb) + { + deleteStatsGrpInfo(inst, grpInfoDb); + SCH_FREE(grpInfoDb, sizeof(SchStatsGrp)); + } + statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].groupId = grpInfo->groupId; + statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].cause = cause; + statsRsp->numGrpRejected++; + return RFAILED; + } + return ROK; +} - isUlTotlPrbUseCfgd = true; - break; - } - default: - { - DU_LOG("\nERROR --> SCH : Invalid statistics type [%d]", statsReq->statsList[idx].type); - rsp = RSP_NOK; - cause = PARAM_INVALID; - } - } /* End of switch */ +/******************************************************************* + * + * @brief Processes Statistics Request from MAC + * + * @details + * + * Function : SchProcStatsReq + * + * Functionality: + * + * This function process the statistics request from MAC: + * [Step 1] Basic validation. If fails, all stats group in stats request are + * rejected. + * [Step 2] If basic validations passed, traverse all stats group and + * validate each measurement types in each group. + * [Step 3] If any measurement type validation fails in a group, that group + * is not configured and it is added to stats-group-rejected-list in + * sch-stats-response message. + * [Step 4] If a group passes all validation, it is added to SCH database. + * And the group is added to stats-group-accepted-list in sch-stats-response message. + * [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list + * and stats-group-accepted-list. + * + * @params[in] Post structure + * Statistics Request from MAC + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq) +{ + bool allocFailed = false; + uint8_t grpIdx = 0, reqGrpIdx = 0; + SchStatsGrpInfo *grpInfo = NULLP; + SchStatsRsp schStatsRsp; + Inst inst = pst->dstInst - SCH_INST_START; + + DU_LOG("\nINFO --> SCH : Received Statistics Request from MAC"); + + if(statsReq == NULLP) + { + DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Received Null pointer"); + return RFAILED; + } + + /*Step -1*/ + if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP) + { + DU_LOG("\nERROR --> SCH : SchProcStatsReq: Maximum number of statistics configured. \ + Cannot process new request."); + SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE); + SCH_FREE(statsReq, sizeof(SchStatsReq)); + return RFAILED; + } + + memset(&schStatsRsp, 0, sizeof(SchStatsRsp)); - if(rsp == RSP_NOK) + /*Step -2*/ + for(reqGrpIdx=0; reqGrpIdxnumStatsGroup && grpIdxstatsGrpList[reqGrpIdx]; + /*Step -3 */ + if(allocFailed == true) + { + schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId; + schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE; + schStatsRsp.numGrpRejected++; + } + else { - /* If failed to configure any KPI, then clear configuration of other - * KPIs that were configured successfully as part of this statsReq */ - if(isDlTotlPrbUseCfgd) + /*Step -4 */ + if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK) { - if((schChkTmr((PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR)) == FALSE) - { - schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR); + DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Failed to fill the stats group list"); + if((schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].groupId == grpInfo->groupId &&\ + (schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE))) + { + allocFailed = true; } - SCH_FREE(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage)); } + } + } + + schStatsRsp.subscriptionId = statsReq->subscriptionId; + SCH_FREE(statsReq, sizeof(SchStatsReq)); + + /*Step -5 */ + SchSendStatsRspToMac(&schStatsRsp); + + return ROK; +} + +/******************************************************************* + * + * @brief Fill and send statistics indication to MAC + * + * @details + * + * Function : SchSendStatsIndToMac + * + * Functionality: Fill and send statistics indication to MAC + * + * @params[in] SCH Instance + * Measurement Type + * Measurement Value + * Size of value parameter + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd *statsInd) +{ + Pst pst; + uint8_t ret = ROK; + +#ifdef DEBUG_PRINT + DU_LOG("\nDEBUG --> SCH : Filling statistics indication"); +#endif + + /* Filling post structure */ + memset(&pst, 0, sizeof(Pst)); + FILL_PST_SCH_TO_MAC(pst, inst); + pst.event = EVENT_STATISTICS_IND_TO_MAC; + + ret = MacMessageRouter(&pst, (void *)statsInd); + if(ret == RFAILED) + { + DU_LOG("\nERROR --> SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication"); + } + return ret; +} + +/** + * @brief Handler to process Timer expiry of DL Total PRB Usage calculation + * + * @param[in] cb Control block depending on the type of the timer event. + * @param[in] tmrEvnt Timer event to be started + * + * @return Bool indicating whether the timer is running or not + * -# ROK + * -# RFAILED +*/ +double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage) +{ + double percentageOfTotalPrbUsed = 0; + + if(dlTotalPrbUsage->totalPrbAvailForTx) + percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx); + + memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage)); + + return percentageOfTotalPrbUsed; +} + +/** + * @brief Handler to check if the timer is running + * + * @param[in] cb Control block depending on the type of the timer event. + * @param[in] tmrEvnt Timer event to be started + * + * @return Bool indicating whether the timer is running or not + * -# ROK + * -# RFAILED +*/ +uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage) +{ + double percentageOfTotalPrbUsed = 0; + + if(ulTotalPrbUsage->totalPrbAvailForTx) + percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx); + + memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage)); + + return percentageOfTotalPrbUsed; +} + +/** + * @brief Calculates statistics in a group and sends + * statistics indication for this group + * + * @param[in] Statistics group info + * + * @return + * -# ROK + * -# RFAILED +*/ +uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo) +{ + uint8_t measStatsIdx = 0; + SchStatsInd statsInd; + + memset(&statsInd, 0, sizeof(SchStatsInd)); + statsInd.subscriptionId = grpInfo->subscriptionId; + statsInd.groupId = grpInfo->groupId; + + if(grpInfo->kpiStats.dlTotalPrbUsage) + { + statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE; + statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage); + measStatsIdx++; + } + + if(grpInfo->kpiStats.ulTotalPrbUsage) + { + statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE; + statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage); + measStatsIdx++; + } + + statsInd.numStats = measStatsIdx; + + return SchSendStatsIndToMac(grpInfo->schInst, &statsInd); +} + +/******************************************************************* + * + * @brief Delete node from active kpi list + * + * @details + * + * Function :deleteNodeFrmKpiList + * + * Functionality: + * Delete statistics group + * + * @params[in] + * Kpi list from which a node needs to be deleted + * Nodes info which a node needs to be deleted + * @return void + * ****************************************************************/ + +void deleteNodeFrmKpiList(CmLListCp *kpiList, PTR kpiNodeInfoToDel) +{ + CmLList *kpiNode=NULLP; + + CM_LLIST_FIRST_NODE(kpiList, kpiNode); + while(kpiNode) + { + if(kpiNode->node == kpiNodeInfoToDel) + { + cmLListDelFrm(kpiList, kpiNode); + SCH_FREE(kpiNode, sizeof(CmLList)); + break; + } + kpiNode = kpiNode->next; + } + +} + +/******************************************************************* + * + * @brief Delete statistics group info + * + * @details + * + * Function : deleteStatsGrpInfo + * + * Functionality: + * Delete statistics group info + * + * @params[in] + * Inst + * Stats Grp info + * @return void + * + * ****************************************************************/ +void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo) +{ + if(statsGrpInfo) + { + if(statsGrpInfo->kpiStats.dlTotalPrbUsage) + { + deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR) statsGrpInfo->kpiStats.dlTotalPrbUsage); + SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage)); + } - if(isUlTotlPrbUseCfgd) + if(statsGrpInfo->kpiStats.ulTotalPrbUsage) + { + deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR) statsGrpInfo->kpiStats.ulTotalPrbUsage); + SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage)); + } + + if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true) + { + schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR); + } + + memset(statsGrpInfo, 0, sizeof(SchStatsGrp)); + } +} + +/******************************************************************* + * + * @brief Delete statistics group Node + * + * @details + * + * Function : deleteStatsGrpNode + * + * Functionality: + * Delete statistics group node + * + * @params[in] + * Inst + * Stats Grp Node + * @return void + * + * ****************************************************************/ +void deleteStatsGrpNode(Inst inst, CmLList *grpNode) +{ + SchStatsGrp *statsGrpInfo=NULLP; + + if(grpNode) + { + statsGrpInfo = (SchStatsGrp*)grpNode->node; + deleteStatsGrpInfo(inst, statsGrpInfo); + memset(statsGrpInfo, 0, sizeof(SchStatsGrp)); + SCH_FREE(grpNode->node, sizeof(SchStatsGrp)); + SCH_FREE(grpNode, sizeof(CmLList)); + } +} + +/****************************************************************** + * + * @brief Deletion of node from statistics group list + * + * @details + * + * Function : deleteFromStatsGrpList + * + * Functionality: Deletion of node from statistics group list + * [Step 1]: Traverse each and every node of stats group list + * stored in the database + * [Step 2]: Check if the node's subscription id is same + * as the subscription id received. If same then go to step 3 + * else move to the next node of the list. + * [Step 3]: If deleteAllGrp == true, then delete the node and + * move to the next node of the list. + * [Step 4]: If deleteAllGrp != true, then check if the node's group + * id is same as group id received then delete the node and mark the + * status found true else move to the next node of the list. + * [Step 5]: Once the traversing complete, + * if deleteAllGrp is true, then return successful rsp; + * else if status found is true, then return successful rsp; + * else return failure. + * @params[in] + * Inst + * Stats Grp List + * Subscription Id + * Group Id + * boolen of deleteAllGrp + * @return void + * + * ****************************************************************/ +uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t subscriptionId, uint8_t groupId, bool deleteAllGrp) +{ + bool statsFound=false; + SchStatsGrp *statsGrpInfo=NULLP; + CmLList *grpNode=NULLP; + + /* [Step 1] */ + CM_LLIST_FIRST_NODE(statsGrpList, grpNode); + while(grpNode) + { + statsGrpInfo = (SchStatsGrp*)grpNode->node; + + /* [Step 2] */ + if(statsGrpInfo->subscriptionId== subscriptionId) + { + if(deleteAllGrp == true) { - if((schChkTmr((PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR)) == FALSE) + /* [Step 3] */ + cmLListDelFrm(statsGrpList, grpNode); + deleteStatsGrpNode(inst, grpNode); + } + else + { + /* [Step 4] */ + if(statsGrpInfo->groupId== groupId) { - schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR); + cmLListDelFrm(statsGrpList, grpNode); + deleteStatsGrpNode(inst, grpNode); + statsFound = true; } - SCH_FREE(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage)); } - break; } - } /* End of FOR */ + CM_LLIST_FIRST_NODE(statsGrpList, grpNode); + } - SCH_FREE(statsReq, sizeof(SchStatsReq)); + /* [Step 5] */ + if(deleteAllGrp == true) + { + return ROK; + } + else + { + if(statsFound == true) + return ROK; + } + return RFAILED; +} - SchSendStatsRspToMac(inst, rsp, cause); +/******************************************************************* + * + * @brief Delete statistics information + * + * @details + * + * Function : deleteStatsInfo + * + * Functionality: + * Delete statistics information base on numStatsGroup + * Info- If numStatsGroup = 0' indicates the Deletion procedure triggered by + * 'SUBS_DELETION_REQ' wherein all the groups of this particular + * Subscription has to be removed + * else when numStatsGroup != 0 then this is + * for SUBS_MOD_REQ's actionToBeDeleted wherein particular action(s) has + * to be removed thus need to pass groupId belonging to that subscription + * which has to be deleted.' + * + * [Step-1] If numStatsGroup = 0, Deletion of all stats group belonging to + * received subscription Id. + * [Step-2] Else if numStatsGroup > 0, Deletion of individual stats group + * from list whose information are present in stats delete request. + * [Step-3] Fill the result of the stats deletion in the SCH stats delete + * response + * @params[in] + * Instance + * Subscription delete req + * Subscription delete rsp + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t deleteStatsInfo(Inst inst, SchStatsDeleteReq *statsDeleteReq, SchStatsDeleteRsp *schStatsDeleteRsp) +{ + uint8_t statsGrpIdx=0; + CmLListCp *statsGrpList =NULLP; + statsGrpList = &schCb[inst].statistics.statsGrpList; + + if(!statsDeleteReq->numStatsGroupToBeDeleted) + { + /* [Step-1] */ + if(deleteFromStatsGrpList(inst,statsGrpList, statsDeleteReq->subscriptionId, 0, true) == ROK) + { + /* [Step 3]*/ + schStatsDeleteRsp->subsDelRsp = RSP_OK; + schStatsDeleteRsp->subsDelCause = SUCCESSFUL; + } + else + { + /* [Step-3]*/ + schStatsDeleteRsp->subsDelRsp = RSP_NOK; + schStatsDeleteRsp->subsDelCause = STATS_ID_NOT_FOUND; + } + } + else + { + for(statsGrpIdx=0; statsGrpIdxnumStatsGroupToBeDeleted; statsGrpIdx++) + { + /* [Step-2] */ + if(deleteFromStatsGrpList(inst, statsGrpList, statsDeleteReq->subscriptionId,\ + statsDeleteReq->statsGrpIdToBeDelList[statsGrpIdx], false) == ROK) + { + /* [Step-3]*/ + schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_OK; + schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = SUCCESSFUL; + } + else + { + /* [Step-3]*/ + schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_NOK; + schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = STATS_ID_NOT_FOUND; + } + } + schStatsDeleteRsp->numStatsGroupDeleted = statsDeleteReq->numStatsGroupToBeDeleted; + } return ROK; -} /* End of SchProcStatsReq */ +} + +/******************************************************************* + * + * @brief Processes Statistics Delete Request from MAC + * + * @details + * + * Function : SchProcStatsDeleteReq + * + * Functionality: + * This function process the statistics delete request from MAC: + * + * @params[in] Post structure + * Statistics Delete Request from MAC + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq) +{ + Pst rspPst; + uint8_t ret =ROK; + SchStatsDeleteRsp *schStatsDeleteRsp; + Inst inst = pst->dstInst - SCH_INST_START; + + DU_LOG("\nINFO --> SCH : Received Statistics Delete Request from MAC"); + if(statsDeleteReq == NULLP) + { + DU_LOG("\nERROR --> SCH : SchProcStatsDeleteReq(): Received Null pointer"); + return RFAILED; + } + + /* Process Stats delete request and fill stats delete response simultaneously */ + SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp)); + if(schStatsDeleteRsp == NULLP) + { + DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchProcStatsDeleteReq()"); + return RFAILED; + } + schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId; + deleteStatsInfo(inst, statsDeleteReq, schStatsDeleteRsp); + + memset(&rspPst, 0, sizeof(Pst)); + FILL_PST_SCH_TO_MAC(rspPst, inst); + rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC; + + ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp); + if(ret == RFAILED) + { + DU_LOG("\nERROR --> SCH : SchProcStatsDeleteReq(): Failed to send Statistics Response"); + } + SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq)); + + return ret; +} /* End of SchProcStatsDeleteReq */ + +/******************************************************************* + * + * @brief Fill and send statistics modification response to MAC + * + * @details + * + * Function : SchSendStatsRspToMac + * + * Functionality: Fill and send statistics + * modification response to MAC + * + * @params[in] Inst inst, SchMacRsp result + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t SchSendStatsModificationRspToMac(SchStatsModificationRsp *tmpSchStatsModRsp) +{ + Pst rspPst; + uint8_t ret = ROK; + SchStatsModificationRsp *schStatsModificationRsp=NULLP; + + DU_LOG("\nINFO --> SCH : Filling statistics modification response"); + SCH_ALLOC(schStatsModificationRsp, sizeof(SchStatsModificationRsp)); + if(schStatsModificationRsp == NULLP) + { + DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsModificationRspToMac()"); + return RFAILED; + } + + memcpy(schStatsModificationRsp, tmpSchStatsModRsp, sizeof(SchStatsModificationRsp)); + memset(tmpSchStatsModRsp, 0, sizeof(SchStatsModificationRsp)); + + /* Filling response post */ + memset(&rspPst, 0, sizeof(Pst)); + FILL_PST_SCH_TO_MAC(rspPst, inst); + rspPst.event = EVENT_STATISTICS_MODIFY_RSP_TO_MAC; + + ret = MacMessageRouter(&rspPst, (void *)schStatsModificationRsp); + if(ret == RFAILED) + { + DU_LOG("\nERROR --> SCH : SchSendStatsModificationRspToMac(): Failed to send Statistics Modification Response"); + return ret; + } + return ret; +} + +/******************************************************************* + * + * @brief Rejects all statistics modification group requested by MAC + * + * @details + * + * Function : SchRejectAllStatsModification + * + * Functionality: Add all statistics modification group received in statistics + * request from MAC, to Reject-StatsModification-Group-List in statistics + * response to MAC + * + * @params[in] Statistics request from MAC + * Cause of rejection + * @return ROK - success + * RFAILED - failure + * + * ****************************************************************/ +uint8_t SchRejectAllStatsModification(SchStatsModificationReq *statsModificationReq, CauseOfResult cause) +{ + uint8_t grpIdx = 0; + SchStatsModificationRsp statsModificationRsp; + + memset(&statsModificationRsp, 0, sizeof(SchStatsModificationRsp)); + + /* fill the subscriptionId and the rejected list in stats modification rsp */ + statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId; + for(grpIdx = 0; grpIdx < statsModificationReq->numStatsGroup; grpIdx++) + { + statsModificationRsp.statsGrpRejectedList[grpIdx].groupId = statsModificationReq->statsGrpList[grpIdx].groupId; + statsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause; + } + statsModificationRsp.numGrpRejected = statsModificationReq->numStatsGroup; + + return SchSendStatsModificationRspToMac(&statsModificationRsp); +} + +/**************************************************************************************** +* +* @brief Processes Statistics modification Request from MAC +* +* @details +* +* Function :SchProcStatsModificationReq +* +* Functionality: +* This function process the statistics modification request from MAC: +* [Step -1] Check the stored stats group list empty. +* [Step - 1.1] If empty Send the rejected group list to MAC as a stats +* modification response. +* [Step - 1.2] Else go to step 2. +* [Step -2] Traverse all stats group and validate each measurement types in +* each group. +* [Step -3] Check for any failure and if failed fill the remaining group's +* info in rejected list. +* [Step -4] Else Check if the received subscriptionId and groupId match the +* values with the database node. +* [Step -4.1] If matches then follow the below mentioned steps. +* [Step -4.1.1] Stop the timer. +* [Step -4.1.2] Reconfigure stats group by adding a new entry for this +* statsGroup with updated configuration in database. +* [Step -4.1.3] if configured successfully, store stats info into +* stats mod rsp's accepted list, restart timer and go to step 4.1.4 +* [Step -4.1.4] Delete the old entry of this stats group.. +* [Step -4.2] Else fill the group related info in stats modification rsp's +* rejected list. +* [Step -5] Send the stats modification rsp to MAC +* @params[in] Post structure +* Statistics modification Request from MAC +* @return ROK - success +* RFAILED - failure +* +* *******************************************************************************************/ +uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq) +{ + Inst inst; + uint8_t reqGrpIdx=0; + uint64_t subscriptionId =0; + bool allocFailed = false; + bool statsGrpFound= false; + CmLList *grpNode = NULLP; + SchStatsGrp *statsGrpInfo=NULLP; + SchStatsGrpInfo statsGrpToModify; + SchStatsModificationRsp statsModificationRsp; + + inst=pst->dstInst - SCH_INST_START; + + DU_LOG("\nINFO --> SCH : Received Statistics modification request from MAC"); + + if(statsModificationReq == NULLP) + { + DU_LOG("\nERROR --> SCH : SchProcStatsModificationReq(): Received Null pointer"); + return RFAILED; + } + memset(&statsModificationRsp, 0, sizeof(SchStatsRsp)); + + /* [Step -1] */ + if(schCb[inst].statistics.statsGrpList.count) + { + /* [Step -1.2] */ + subscriptionId = statsModificationReq->subscriptionId; + + /* [Step - 2] */ + for(reqGrpIdx=0; reqGrpIdxnumStatsGroup; 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 **********************************************************************/