[ Jira id - ODUHIGH-593 ] Pack and unpack function nomenclature correction
[o-du/l2.git] / src / 5gnrsch / sch.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
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                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
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
19 /************************************************************************
20  
21      Name:     sch.c
22   
23      Type:     C source file
24   
25      Desc:     C source code for scheduler fucntions
26   
27      File:     sch.c
28   
29 **********************************************************************/
30
31 /** @file sch.c
32 @brief This file implements the schedulers main access to MAC layer code.
33 */
34 #include "common_def.h" 
35 #include "du_app_mac_inf.h"
36 #include "lrg.h"
37 #include "tfu.h"
38 #include "du_log.h"
39 #include "rgr.h"
40 #include "rg_sch_inf.h"
41 #include "rg_sch.h"
42
43 #include "tfu.x"           /* TFU types */
44 #include "lrg.x"           /* layer management typedefs for MAC */
45 #include "rgr.x"           /* layer management typedefs for MAC */
46 #include "rg_sch_inf.x"         /* typedefs for Scheduler */
47 #include "mac_sch_interface.h"
48 #include "sch.h"
49 #include "sch_tmr.h"
50 #include "sch_utils.h"
51 #include "sch_fcfs.h"
52 #include "sch_slice_based.h"
53 SchCb schCb[SCH_MAX_INST];
54
55 /**
56  * @brief Scheduler All Apis initialized. 
57  *
58  * @details
59  *
60  *     Function : schAllApisInit
61  *     
62  *     This function initializes all Scheduler APIs/functionality for each kind
63  *     of scheduler type. 
64  *     
65  *  @param[in]  Inst inst, the Scheduler instance 
66  *  @return  void
67  **/
68 void schAllApisInit(Inst inst)
69 {
70     schFcfsAllApisInit(&schCb[inst].allApis[SCH_FCFS]);  
71     schSliceBasedAllApisInit(&schCb[inst].allApis[SCH_SLICE_BASED]);
72 }
73
74 /**
75  * @brief Scheduler instance Configuration Handler. 
76  *
77  * @details
78  *
79  *     Function : SchInstCfg
80  *     
81  *     This function in called by SchProcGenCfgReq(). It handles the
82  *     general configurations of the scheduler instance. Returns
83  *     reason for success/failure of this function.
84  *     
85  *  @param[in]  RgCfg *cfg, the Configuaration information 
86  *  @return  uint16_t
87  *      -# LCM_REASON_NOT_APPL 
88  *      -# LCM_REASON_INVALID_MSGTYPE
89  *      -# LCM_REASON_MEM_NOAVAIL
90  **/
91 uint8_t SchInstCfg(RgCfg *cfg, Inst  dInst)
92 {
93    uint16_t ret = LCM_REASON_NOT_APPL;
94    Inst     inst = (dInst - SCH_INST_START);
95
96    DU_LOG("\nDEBUG  -->  SCH : Entered SchInstCfg()");
97    /* Check if Instance Configuration is done already */
98    if (schCb[inst].schInit.cfgDone == TRUE)
99    {
100       return LCM_REASON_INVALID_MSGTYPE;
101    }
102    /* Update the Pst structure for LM interface */
103    memcpy(&schCb[inst].schInit.lmPst, &cfg->s.schInstCfg.genCfg.lmPst, sizeof(Pst));
104
105    schCb[inst].schInit.inst = inst;
106    schCb[inst].schInit.lmPst.srcProcId = schCb[inst].schInit.procId;
107    schCb[inst].schInit.lmPst.srcEnt = schCb[inst].schInit.ent;
108    schCb[inst].schInit.lmPst.srcInst = schCb[inst].schInit.inst +
109       SCH_INST_START;
110    schCb[inst].schInit.lmPst.event = EVTNONE;
111
112    schCb[inst].schInit.region = cfg->s.schInstCfg.genCfg.mem.region;
113    schCb[inst].schInit.pool = cfg->s.schInstCfg.genCfg.mem.pool;
114 #ifdef LTE_ADV
115    schCb[inst].genCfg.forceCntrlSrbBoOnPCel =  cfg->s.schInstCfg.genCfg.forceCntrlSrbBoOnPCel;
116    schCb[inst].genCfg.isSCellActDeactAlgoEnable =  cfg->s.schInstCfg.genCfg.isSCellActDeactAlgoEnable;
117 #endif
118    schCb[inst].genCfg.startCellId    = cfg->s.schInstCfg.genCfg.startCellId;
119
120    schCb[inst].schTimersInfo.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
121    /* Initialzie the timer queue */   
122    memset(&schCb[inst].schTimersInfo.tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
123    /* Initialize the timer control point */
124    memset(&schCb[inst].schTimersInfo.tmrTqCp, 0, sizeof(CmTqCp));
125    schCb[inst].schTimersInfo.tmrTqCp.tmrLen = SCH_TQ_SIZE;
126
127    /* SS_MT_TMR needs to be enabled as schActvTmr needs instance information */
128    /* Timer Registration request to system services */
129    if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst, (int)schCb[inst].schTimersInfo.tmrRes, schActvTmr) != ROK)
130    {
131       DU_LOG("\nERROR  -->  SCH : SchInstCfg(): Failed to register timer.");
132       return (LCM_REASON_MEM_NOAVAIL);
133    }   
134
135    /* Initialize statistics related configurations */
136    memset(&schCb[inst].statistics, 0, sizeof(SchStatistics));
137    cmLListInit(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList);
138    cmLListInit(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList);
139
140    /* Set Config done in TskInit */
141    schCb[inst].schInit.cfgDone = TRUE;
142    DU_LOG("\nINFO   -->  SCH : Scheduler gen config done");
143    
144    schAllApisInit(inst);
145    return ret;
146 }
147
148 /**
149  * @brief Layer Manager Configuration request handler. 
150  *
151  * @details
152  *
153  *     Function : SchProcGenCfgReq
154  *     
155  *     This function handles the configuration
156  *     request received at scheduler instance from the Layer Manager.
157  *     -# Based on the cfg->hdr.elmId.elmnt value it invokes one of the
158  *        functions rgHdlGenCfg() or rgHdlSapCfg().
159  *     -# Invokes RgMiLrgSchCfgCfm() to send back the confirmation to the LM.
160  *     
161  *  @param[in]  Pst *pst, the post structure     
162  *  @param[in]  RgMngmt *cfg, the configuration parameter's structure
163  *  @return  S16
164  *      -# ROK
165  **/
166 uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
167 {
168    uint8_t   ret = LCM_PRIM_OK;
169    uint16_t  reason = LCM_REASON_NOT_APPL;
170    RgMngmt   cfm;
171    Pst       cfmPst;
172
173    if(pst->dstInst < SCH_INST_START)
174    {
175       DU_LOG("\nERROR  -->  SCH : Invalid inst ID");
176       DU_LOG("\nERROR  -->  SCH : SchProcGenCfgReq(): "
177             "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START); 
178       return ROK;
179    }
180    DU_LOG("\nINFO   -->  SCH : Received scheduler gen config");
181    /* Fill the post structure for sending the confirmation */
182    memset(&cfmPst, 0 , sizeof(Pst));
183    SchFillCfmPst(pst, &cfmPst, cfg);
184
185    memset(&cfm, 0, sizeof(RgMngmt));
186
187 #ifdef LMINT3
188    cfm.hdr.transId =
189       cfg->hdr.transId;
190 #endif
191
192    cfm.hdr.elmId.elmnt = cfg->hdr.elmId.elmnt;
193    switch(cfg->hdr.elmId.elmnt)
194    {
195       case STSCHINST:
196          reason = SchInstCfg(&cfg->t.cfg,pst->dstInst );
197          break;
198       default:
199          ret = LCM_PRIM_NOK;
200          reason = LCM_REASON_INVALID_ELMNT;
201          DU_LOG("\nERROR  -->  SCH : Invalid Elmnt=%d", cfg->hdr.elmId.elmnt);
202          break;
203    }
204
205    if (reason != LCM_REASON_NOT_APPL)
206    {
207       ret = LCM_PRIM_NOK;
208    }
209
210    cfm.cfm.status = ret;
211    cfm.cfm.reason = reason;
212
213    SchSendCfgCfm(&cfmPst, &cfm);
214    /*   SCH_FREE(pst->region, pst->pool, (Data *)cfg, sizeof(RgMngmt)); */
215
216    return ROK;
217 }/*-- SchProcGenCfgReq --*/
218
219 #ifdef NR_TDD
220 /**
221  *@brief Returns TDD periodicity in micro seconds
222  *
223  * @details
224  * 
225  * Function : schGetPeriodicityInMsec 
226  * 
227  * This API retunrs TDD periodicity in micro seconds
228  * 
229  * @param[in] DlUlTxPeriodicity 
230  * @return  periodicityInMsec
231  * **/
232
233 uint16_t schGetPeriodicityInMsec(DlUlTxPeriodicity tddPeriod)
234 {
235    uint16_t  periodicityInMsec = 0;
236    switch(tddPeriod)
237    {
238       case TX_PRDCTY_MS_0P5:
239       {
240          periodicityInMsec = 500;
241          break;
242       }
243       case TX_PRDCTY_MS_0P625:
244       {
245          periodicityInMsec = 625;
246          break;
247       }
248       case TX_PRDCTY_MS_1:
249       {
250          periodicityInMsec = 1000;
251          break;
252       }
253       case TX_PRDCTY_MS_1P25:
254       {
255          periodicityInMsec = 1250;
256          break;
257       }
258       case TX_PRDCTY_MS_2:
259       {
260          periodicityInMsec = 2000;
261          break;
262       }
263       case TX_PRDCTY_MS_2P5:
264       {
265          periodicityInMsec = 2500;
266          break;
267       }
268       case TX_PRDCTY_MS_5:
269       {
270          periodicityInMsec = 5000;
271          break;
272       }
273       case TX_PRDCTY_MS_10:
274       {
275          periodicityInMsec = 10000;
276          break;
277       }
278       default:
279       {
280          DU_LOG("\nERROR  -->  SCH : Invalid DlUlTxPeriodicity:%d", tddPeriod);
281       }
282    }
283
284    return periodicityInMsec;
285 }
286
287 /**
288  *@brief Fills the slotCfg from CellCfg
289  *
290  * @details
291  * 
292  * Function : schFillSlotConfig 
293  * 
294  * This API Fills the slotCfg from CellCfg
295  * 
296  * @param[in] SchCellCb *cell, TDDCfg tddCfg
297  * @return  void
298  * **/
299 void schFillSlotConfig(SchCellCb *cell, TDDCfg tddCfg)
300 {
301    uint8_t slotIdx = 0, symbolIdx = 0;
302
303    for(slotIdx =0 ;slotIdx < MAX_TDD_PERIODICITY_SLOTS; slotIdx++) 
304    {
305       for(symbolIdx = 0; symbolIdx < MAX_SYMB_PER_SLOT; symbolIdx++)
306       {
307          /*Fill Full-DL Slots as well as DL symbols ini 1st Flexi Slo*/
308          if(slotIdx < tddCfg.nrOfDlSlots || \
309                (slotIdx == tddCfg.nrOfDlSlots && symbolIdx < tddCfg.nrOfDlSymbols)) 
310          {
311               cell->slotCfg[slotIdx][symbolIdx] = DL_SYMBOL; 
312          }
313
314          /*Fill Full-FLEXI SLOT and as well as Flexi Symbols in 1 slot preceding FULL-UL slot*/ 
315          else if(slotIdx < (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) ||  \
316                (slotIdx == (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) && \
317                 symbolIdx < (MAX_SYMB_PER_SLOT - tddCfg.nrOfUlSymbols)))
318          {
319               cell->slotCfg[slotIdx][symbolIdx] = FLEXI_SYMBOL; 
320          }
321          /*Fill Partial UL symbols and Full-UL slot*/
322          else
323          {
324               cell->slotCfg[slotIdx][symbolIdx] = UL_SYMBOL; 
325          }
326       }
327    }
328 }
329
330 /**
331  * @brief init TDD slot config 
332  *
333  * @details
334  *
335  *     Function : schInitTddSlotCfg 
336  *      
337  *      This API is invoked after receiving schCellCfg
338  *           
339  *  @param[in]  schCellCb *cell
340  *  @param[in]  SchCellCfg *schCellCfg
341  *  @return  void
342  **/
343 void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
344 {
345    uint16_t periodicityInMicroSec = 0;
346    int8_t slotIdx, symbIdx;
347
348    periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
349    cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, cell->numerology))/1000;
350    cell->slotFrmtBitMap = 0;
351    schFillSlotConfig(cell, schCellCfg->tddCfg);
352    for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
353    {
354       symbIdx = 0;
355       /* If the first and last symbol are the same, the entire slot is the same type */
356       if((cell->slotCfg[slotIdx][symbIdx] == cell->slotCfg[slotIdx][MAX_SYMB_PER_SLOT-1]) &&
357               cell->slotCfg[slotIdx][symbIdx] != FLEXI_SYMBOL)
358       {
359          switch(cell->slotCfg[slotIdx][symbIdx])
360          {
361             case DL_SLOT:
362             {
363                /*BitMap to be set to 00 */
364                cell->slotFrmtBitMap = (cell->slotFrmtBitMap<<2);
365                break;
366             }
367             case UL_SLOT:
368             {
369                /*BitMap to be set to 01 */
370                cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (UL_SLOT));
371                break;
372             }
373             default:
374                DU_LOG("\nERROR  -->  SCH : Invalid slot Config in schInitTddSlotCfg");
375            }
376          continue;
377       }
378       /* slot config is flexible. First set slotBitMap to 10 */
379       cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (FLEXI_SLOT));
380    }
381 }
382 #endif
383
384 /**
385  * @brief Fill SSB start symbol
386  *
387  * @details
388  *
389  *     Function : fillSsbStartSymb 
390  *      
391  *      This API stores SSB start index per beam
392  *           
393  *  @param[in]  SchCellCb     *cellCb
394  *  @return  int
395  *      -# ROK 
396  *      -# RFAILED 
397  **/
398 void fillSsbStartSymb(SchCellCb *cellCb)
399 {
400    uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
401
402    scs = cellCb->cellCfg.ssbScs;
403
404    memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
405    symbIdx = 0;
406    /* Determine value of "n" based on Section 4.1 of 3GPP TS 38.213 */
407    switch(scs)
408    {
409       case SCS_15KHZ:
410          {
411             if(cellCb->cellCfg.ssbFrequency <= 300000)
412                cnt = 2;/* n = 0, 1 */
413             else
414                cnt = 4; /* n = 0, 1, 2, 3 */
415             for(uint8_t idx=0; idx<cnt; idx++)
416             {
417                /* start symbol determined using {2, 8} + 14n */
418                ssbStartSymbArr[symbIdx++] = 2 +  MAX_SYMB_PER_SLOT*idx;
419                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
420             }
421          }
422          break;
423       case SCS_30KHZ:
424          {
425             if(cellCb->cellCfg.ssbFrequency <= 300000)
426                cnt = 1;/* n = 0 */
427             else
428                cnt = 2; /* n = 0, 1 */
429             for(uint8_t idx=0; idx<cnt; idx++)
430             {
431                /* start symbol determined using {4, 8, 16, 20} + 28n */
432                ssbStartSymbArr[symbIdx++] = 4 +  MAX_SYMB_PER_SLOT*idx;
433                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
434                ssbStartSymbArr[symbIdx++] = 16 +  MAX_SYMB_PER_SLOT*idx;
435                ssbStartSymbArr[symbIdx++] = 20 +  MAX_SYMB_PER_SLOT*idx;
436             }
437          }
438          break;
439       default:
440          DU_LOG("\nERROR  -->  SCH : SCS %d is currently not supported", scs);
441    }
442    memset(cellCb->ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
443    memcpy(cellCb->ssbStartSymbArr, ssbStartSymbArr, SCH_MAX_SSB_BEAM);
444 }
445
446
447 /**
448  * @brief init cellCb based on cellCfg
449  *
450  * @details
451  *
452  *     Function : schInitCellCb 
453  *      
454  *      This API is invoked after receiving schCellCfg
455  *           
456  *  @param[in]  schCellCb *cell
457  *  @param[in]  SchCellCfg *schCellCfg
458  *  @return  int
459  *      -# ROK 
460  *      -# RFAILED 
461  **/
462 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
463 {
464    uint16_t scsInKhz = 0;
465    SchCellCb *cell= NULLP;
466    SCH_ALLOC(cell, sizeof(SchCellCb));
467    if(!cell)
468    {
469       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
470       return RFAILED;
471    }
472
473    cell->cellId = schCellCfg->cellId; 
474    cell->instIdx = inst;
475    scsInKhz = convertScsEnumValToScsVal(schCellCfg->ssbScs);
476    
477    /*Ref : 3GPP 38.211 Table 4.2-1: SCS = (2 ^ numerology * 15kHz)*/
478    cell->numerology = log2(scsInKhz/BASE_SCS);
479    switch(cell->numerology)
480    {
481       case SCH_NUMEROLOGY_0:
482          {
483             cell->numSlots = SCH_MU0_NUM_SLOTS;
484          }
485          break;
486       case SCH_NUMEROLOGY_1:
487          {
488             cell->numSlots = SCH_MU1_NUM_SLOTS;
489          }
490          break;
491       case SCH_NUMEROLOGY_2:
492          {
493             cell->numSlots = SCH_MU2_NUM_SLOTS;
494          }
495          break;
496       case SCH_NUMEROLOGY_3:
497          {
498             cell->numSlots = SCH_MU3_NUM_SLOTS;
499          }
500          break;
501       case SCH_NUMEROLOGY_4:
502          {
503             cell->numSlots = SCH_MU4_NUM_SLOTS;
504          }
505          break;
506       default:
507          DU_LOG("\nERROR  -->  SCH : Numerology %d not supported", cell->numerology);
508    }
509 #ifdef NR_TDD
510    schInitTddSlotCfg(cell, schCellCfg);   
511 #endif
512
513    SCH_ALLOC(cell->schDlSlotInfo, cell->numSlots * sizeof(SchDlSlotInfo*));
514    if(!cell->schDlSlotInfo)
515    {
516       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schDlSlotInfo");
517       return RFAILED;
518    }
519
520    SCH_ALLOC(cell->schUlSlotInfo, cell->numSlots * sizeof(SchUlSlotInfo*));
521    if(!cell->schUlSlotInfo)
522    {
523       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schUlSlotInfo");
524       return RFAILED;
525    }
526
527    for(uint8_t idx=0; idx<cell->numSlots; idx++)
528    {
529       SchDlSlotInfo *schDlSlotInfo;
530       SchUlSlotInfo *schUlSlotInfo;
531
532       /* DL Alloc */
533       SCH_ALLOC(schDlSlotInfo, sizeof(SchDlSlotInfo));
534       if(!schDlSlotInfo)
535       {
536          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
537          return RFAILED;
538       }
539
540       /* UL Alloc */
541       SCH_ALLOC(schUlSlotInfo, sizeof(SchUlSlotInfo));
542       if(!schUlSlotInfo)
543       {
544          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
545          return RFAILED;
546       }
547
548       schInitDlSlot(schDlSlotInfo);
549       schInitUlSlot(schUlSlotInfo);
550
551       cell->schDlSlotInfo[idx] = schDlSlotInfo;
552       cell->schUlSlotInfo[idx] = schUlSlotInfo;
553
554    }
555    cell->firstSsbTransmitted = false;
556    cell->firstSib1Transmitted = false;
557    fillSsbStartSymb(cell);
558
559 #ifdef NR_DRX
560    memset(cell->drxCb, 0, MAX_DRX_SIZE*sizeof(SchDrxCb));
561 #endif   
562    schCb[inst].cells[inst] = cell;
563
564    DU_LOG("\nINFO  -->  SCH : Cell init completed for cellId:%d", cell->cellId);
565
566    return ROK;   
567 }
568
569 /**
570  * @brief Fill SIB1 configuration
571  *
572  * @details
573  *
574  *     Function : fillSchSib1Cfg
575  *
576  *     Fill SIB1 configuration
577  *
578  *  @param[in]  uint8_t bandwidth : total available bandwidth
579  *              uint8_t numSlots : total slots per SFN
580  *              SchSib1Cfg *sib1SchCfg : cfg to be filled
581  *              uint16_t pci : physical cell Id
582  *              uint8_t offsetPointA : offset
583  *  @return  void
584  **/
585 uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchConfigSib1 *pdcchCfgSib1,\
586                SchSib1Cfg *sib1SchCfg, uint16_t pci, uint8_t offsetPointA, uint16_t sib1PduLen)
587 {
588    uint8_t coreset0Idx = 0;
589    uint8_t searchSpace0Idx = 0;
590    //uint8_t ssbMuxPattern = 0;
591    uint8_t numRbs = 0;
592    uint8_t numSymbols = 0;
593    uint8_t offset = 0;
594    uint8_t oValue = 0;
595    //uint8_t numSearchSpacePerSlot = 0;
596    uint8_t mValue = 0;
597    uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
598    uint8_t slotIndex = 0;
599    uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
600    uint16_t tbSize = 0;
601    uint8_t ssbIdx = 0;
602    PdcchCfg *pdcch;
603    PdschCfg *pdsch;
604    BwpCfg *bwp;
605
606    pdcch = &(sib1SchCfg->sib1PdcchCfg);
607    bwp = &(sib1SchCfg->bwp);
608
609    coreset0Idx     = pdcchCfgSib1->coresetZeroIndex;
610    searchSpace0Idx = pdcchCfgSib1->searchSpaceZeroIndex;
611
612    /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
613    //ssbMuxPattern = coresetIdxTable[coreset0Idx][0];
614    numRbs        = coresetIdxTable[coreset0Idx][1];
615    numSymbols    = coresetIdxTable[coreset0Idx][2];
616    offset        = coresetIdxTable[coreset0Idx][3];
617
618    /* derive the search space params from table 13-11 spec 38.213 */
619    oValue                = searchSpaceIdxTable[searchSpace0Idx][0];
620    //numSearchSpacePerSlot = searchSpaceIdxTable[searchSpace0Idx][1];
621    mValue                = searchSpaceIdxTable[searchSpace0Idx][2];
622    firstSymbol           = searchSpaceIdxTable[searchSpace0Idx][3];
623
624    /* calculate the n0, need to add the formulae, as of now the value is 0 
625     * Need to add the even and odd values of i during configuration 
626     * [(O . 2^u + i . M )  ] mod numSlotsPerSubframe 
627     * assuming u = 0, i = 0, numSlotsPerSubframe = 10
628     * Also, from this configuration, coreset0 is only on even subframe */
629    slotIndex = (int)((oValue*pow(2, mu)) + floor(ssbIdx*mValue))%numSlots;
630    sib1SchCfg->n0 = slotIndex;
631
632    /* fill BWP */
633    switch(bandwidth)
634    {
635       case BANDWIDTH_20MHZ:
636          {
637             bwp->freqAlloc.numPrb = TOTAL_PRB_20MHZ_MU0;
638          }
639          break;
640       case BANDWIDTH_100MHZ:
641          {
642             bwp->freqAlloc.numPrb = TOTAL_PRB_100MHZ_MU1;
643          }
644          break;
645       default:
646          DU_LOG("\nERROR  -->  SCH : Bandwidth %d not supported", bandwidth);
647
648    }
649    bwp->freqAlloc.startPrb = 0;
650    bwp->subcarrierSpacing  = 0;         /* 15Khz */
651    bwp->cyclicPrefix       = 0;              /* normal */
652
653    /* fill the PDCCH PDU */
654    pdcch->coresetCfg.coreSetSize = numRbs;
655    pdcch->coresetCfg.startSymbolIndex = firstSymbol;
656    pdcch->coresetCfg.durationSymbols = numSymbols;
657    
658    /* Fill Bitmap for PRBs in coreset */
659    fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), freqDomainResource);
660    memcpy(pdcch->coresetCfg.freqDomainResource, freqDomainResource, FREQ_DOM_RSRC_SIZE);
661
662    pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
663    pdcch->coresetCfg.regBundleSize = 6;    /* spec-38.211 sec 7.3.2.2 */
664    pdcch->coresetCfg.interleaverSize = 2;  /* spec-38.211 sec 7.3.2.2 */
665    pdcch->coresetCfg.coreSetType = 0;
666    pdcch->coresetCfg.shiftIndex = pci;
667    pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
668    pdcch->numDlDci = 1;
669    pdcch->dci[0].rnti = SI_RNTI;
670    pdcch->dci[0].scramblingId = pci;
671    pdcch->dci[0].scramblingRnti = 0;
672    pdcch->dci[0].cceIndex = 0;
673    pdcch->dci[0].aggregLevel = 4;
674    pdcch->dci[0].beamPdcchInfo.numPrgs = 1;
675    pdcch->dci[0].beamPdcchInfo.prgSize = 1;
676    pdcch->dci[0].beamPdcchInfo.digBfInterfaces = 0;
677    pdcch->dci[0].beamPdcchInfo.prg[0].pmIdx = 0;
678    pdcch->dci[0].beamPdcchInfo.prg[0].beamIdx[0] = 0;
679    pdcch->dci[0].txPdcchPower.beta_pdcch_1_0= 0;
680    pdcch->dci[0].txPdcchPower.powerControlOffsetSS = 0;
681    /* Storing pdschCfg pointer here. Required to access pdsch config while
682       fillig up pdcch pdu */
683    pdsch = &pdcch->dci[0].pdschCfg; 
684
685    /* fill the PDSCH PDU */
686    uint8_t cwCount = 0;
687    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
688    pdsch->rnti = 0xFFFF; /* SI-RNTI */
689    pdsch->pduIndex = 0;
690    pdsch->numCodewords = 1;
691    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
692    {
693       pdsch->codeword[cwCount].targetCodeRate = 308;
694       pdsch->codeword[cwCount].qamModOrder = 2;
695       pdsch->codeword[cwCount].mcsIndex = DEFAULT_MCS;
696       pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
697       pdsch->codeword[cwCount].rvIndex = 0;
698       tbSize = schCalcTbSize(sib1PduLen + TX_PAYLOAD_HDR_LEN);
699       pdsch->codeword[cwCount].tbSize = tbSize;
700    }
701    pdsch->dataScramblingId                   = pci;
702    pdsch->numLayers                          = 1;
703    pdsch->transmissionScheme                 = 0;
704    pdsch->refPoint                           = 0;
705    pdsch->dmrs.dlDmrsSymbPos                 = DL_DMRS_SYMBOL_POS; 
706    pdsch->dmrs.dmrsConfigType                = 0; /* type-1 */
707    pdsch->dmrs.dlDmrsScramblingId            = pci;
708    pdsch->dmrs.scid                          = 0;
709    pdsch->dmrs.numDmrsCdmGrpsNoData          = 1;
710    pdsch->dmrs.dmrsPorts                     = 0x0001;
711    pdsch->dmrs.mappingType                   = DMRS_MAP_TYPE_A; /* Type-A */
712    pdsch->dmrs.nrOfDmrsSymbols               = NUM_DMRS_SYMBOLS;
713    pdsch->dmrs.dmrsAddPos                    = DMRS_ADDITIONAL_POS;
714
715    pdsch->pdschFreqAlloc.resourceAllocType   = 1; /* RAT type-1 RIV format */
716    /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
717    pdsch->pdschFreqAlloc.startPrb  = offsetPointA + SCH_SSB_NUM_PRB;
718    pdsch->pdschFreqAlloc.numPrb    = schCalcNumPrb(tbSize, DEFAULT_MCS, NUM_PDSCH_SYMBOL);
719    pdsch->pdschFreqAlloc.vrbPrbMapping       = 0; /* non-interleaved */
720    pdsch->pdschTimeAlloc.rowIndex            = 1;
721    /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
722    pdsch->pdschTimeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
723    pdsch->pdschTimeAlloc.numSymb   = NUM_PDSCH_SYMBOL;
724    pdsch->beamPdschInfo.numPrgs              = 1;
725    pdsch->beamPdschInfo.prgSize              = 1;
726    pdsch->beamPdschInfo.digBfInterfaces      = 0;
727    pdsch->beamPdschInfo.prg[0].pmIdx         = 0;
728    pdsch->beamPdschInfo.prg[0].beamIdx[0]    = 0;
729    pdsch->txPdschPower.powerControlOffset    = 0;
730    pdsch->txPdschPower.powerControlOffsetSS  = 0;
731
732    return ROK;
733 }
734
735 /**
736  * @brief cell config from MAC to SCH.
737  *
738  * @details
739  *
740  *     Function : macSchCellCfgReq
741  *      
742  *      This API is invoked by MAC to send cell config to SCH
743  *           
744  *  @param[in]  Pst            *pst
745  *  @param[in]  SchCellCfg     *schCellCfg
746  *  @return  int
747  *      -# ROK 
748  *      -# RFAILED 
749  **/
750 uint8_t SchProcCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
751 {
752    uint8_t ret = ROK;
753    SchCellCb *cellCb;
754    SchCellCfgCfm schCellCfgCfm;
755    Pst rspPst;
756    Inst inst = pst->dstInst - SCH_INST_START; 
757    uint8_t coreset0Idx = 0;
758    uint8_t numRbs = 0;
759    uint8_t offset = 0;
760    uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
761    SchPdschConfig pdschCfg;
762
763    schInitCellCb(inst, schCellCfg);
764    cellCb = schCb[inst].cells[inst]; //cells is of MAX_CELLS, why inst
765    cellCb->macInst = pst->srcInst;
766
767    /* derive the SIB1 config parameters */
768    ret = fillSchSib1Cfg(cellCb->numerology, schCellCfg->dlBandwidth, cellCb->numSlots,
769          &(schCellCfg->pdcchCfgSib1), &(cellCb->sib1SchCfg), schCellCfg->phyCellId,
770          schCellCfg->dlCfgCommon.schFreqInfoDlSib.offsetToPointA, schCellCfg->sib1PduLen);
771    
772    if(ret != ROK)
773    {
774       DU_LOG("\nERROR --> SCH : Failed to fill sib1 configuration");
775       return RFAILED;
776    }
777    memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
778    schProcPagingCfg(cellCb);
779
780    /* Fill coreset frequencyDomainResource bitmap */
781    coreset0Idx = cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
782    numRbs = coresetIdxTable[coreset0Idx][1];
783    offset = coresetIdxTable[coreset0Idx][3];
784    fillCoresetFeqDomAllocMap(((cellCb->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA - offset)/6), \
785                                   (numRbs/6), freqDomainResource);
786    memcpy(cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc,\
787                freqDomainResource,FREQ_DOM_RSRC_SIZE);
788    /* Fill K0 - K1 table for common cfg*/ 
789    BuildK0K1Table(cellCb, &cellCb->k0K1InfoTbl, true, cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon,
790                    pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
791    
792    BuildK2InfoTable(cellCb, cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList,\
793    cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.numTimeDomRsrcAlloc, &cellCb->msg3K2InfoTbl, \
794    &cellCb->k2InfoTbl);
795    
796    /*As per Spec 38.211, Sec 6.3.3.2; RootSeq Len(Lra) where Lra=839 or Lra=139,
797     *depending on the PRACH preamble format as given by Tables 6.3.3.1-1 and 6.3.3.1-2.*/
798    if(prachCfgIdxTable[cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.prachCfgIdx][0] <= 3)
799    {
800       cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_1;
801    }
802    else
803    {
804       cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_2;
805    }
806    /* Initializing global variables */
807    cellCb->actvUeBitMap = 0;
808    cellCb->boIndBitMap = 0;
809
810    cellCb->schHqCfg.maxDlDataHqTx = SCH_MAX_NUM_DL_HQ_TX;
811    cellCb->schHqCfg.maxMsg4HqTx = SCH_MAX_NUM_MSG4_TX;
812    cellCb->schHqCfg.maxUlDataHqTx = SCH_MAX_NUM_UL_HQ_TX;
813    cellCb->maxMsg3Tx = SCH_MAX_NUM_MSG3_TX;
814
815    cellCb->schAlgoType = SCH_FCFS;
816    cellCb->api = &schCb[inst].allApis[cellCb->schAlgoType]; /* For FCFS */
817    cellCb->api->SchCellCfgReq(cellCb);
818    
819    /* Fill and send Cell config confirm */
820    memset(&rspPst, 0, sizeof(Pst));
821    FILL_PST_SCH_TO_MAC(rspPst, pst->dstInst);
822    rspPst.event = EVENT_SCH_CELL_CFG_CFM;
823
824    schCellCfgCfm.cellId = schCellCfg->cellId; 
825    schCellCfgCfm.rsp = RSP_OK;
826
827    ret = MacMessageRouter(&rspPst, (void *)&schCellCfgCfm);
828    return ret;
829
830 }
831
832 /*******************************************************************
833  *
834  * @brief Fill and send Cell delete response to MAC
835  *
836  * @details
837  *
838  *    Function :  SchSendCellDeleteRspToMac
839  *
840  *    Functionality: Fill and send Cell delete response to MAC
841  *
842  * @params[in] SchCellDelete  *ueDelete, Inst inst, SchMacRsp result
843  * @return ROK     - success
844  *         RFAILED - failure
845  *
846  * ****************************************************************/
847 uint8_t SchSendCellDeleteRspToMac(SchCellDeleteReq  *ueDelete, Inst inst, SchMacRsp result)
848 {
849    Pst rspPst;
850    uint8_t ret=0;
851    
852    SchCellDeleteRsp  delRsp;
853
854    DU_LOG("\nINFO   --> SCH : Filling Cell Delete response");
855    memset(&delRsp, 0, sizeof(SchCellDeleteRsp));
856    delRsp.cellId = ueDelete->cellId;
857    delRsp.rsp = result;
858
859    /* Filling response post */
860    memset(&rspPst, 0, sizeof(Pst));
861    FILL_PST_SCH_TO_MAC(rspPst, inst);
862    rspPst.event = EVENT_CELL_DELETE_RSP_TO_MAC;
863    ret = MacMessageRouter(&rspPst, (void *)&delRsp);
864    if(ret == RFAILED)
865    {
866       DU_LOG("\nERROR  -->  SCH : SchSendCellDeleteRspToMac(): failed to send the Cell Delete response");
867       return ret;
868    }
869    return ret;
870 }
871
872 /*******************************************************************
873  *
874  * @brief Function for cellCb Deletion 
875  *
876  * @details
877  *
878  *    Function : deleteSchCellCb 
879  *
880  *    Functionality: Function for cellCb Deletion 
881  *
882  * @params[in] SchCellDelete  *cellDelete
883  * @return ROK     - success
884  *         RFAILED - failure
885  *
886  * ****************************************************************/
887 void deleteSchCellCb(SchCellCb *cellCb)
888 {
889    uint8_t sliceIdx=0, slotIdx=0, plmnIdx = 0;
890    uint8_t ueIdx = 0;
891    CmLListCp *list=NULL;
892    CmLList *node=NULL, *next=NULL;
893    SchPageInfo *tempNode = NULLP;
894
895    if(cellCb->schDlSlotInfo)
896    {
897       for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
898       {
899          list = &cellCb->schDlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
900          node = list->first;
901          while(node)
902          {
903             next = node->next;
904             SCH_FREE(node->node, sizeof(FreePrbBlock));
905             deleteNodeFromLList(list, node);
906             node = next;
907          }
908          for(ueIdx = 0; ueIdx< MAX_NUM_UE; ueIdx++)
909          {
910             SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->rarAlloc[ueIdx], sizeof(RarAlloc));
911             SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->dlMsgAlloc[ueIdx], sizeof(DlMsgSchInfo));
912          }
913          SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->ulGrant, sizeof(DciInfo));
914          SCH_FREE(cellCb->schDlSlotInfo[slotIdx], sizeof(SchDlSlotInfo));
915       }
916       SCH_FREE(cellCb->schDlSlotInfo, cellCb->numSlots *sizeof(SchDlSlotInfo*));
917    }
918
919    if(cellCb->schUlSlotInfo)
920    {
921       for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
922       {
923          list = &cellCb->schUlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
924          node = list->first;
925          while(node)
926          {
927             next = node->next;
928             SCH_FREE(node->node, sizeof(FreePrbBlock));
929             deleteNodeFromLList(list, node);
930             node = next;
931          }
932          for(ueIdx = 0; ueIdx< MAX_NUM_UE; ueIdx++)
933          {
934             SCH_FREE(cellCb->schUlSlotInfo[slotIdx]->schPuschInfo[ueIdx], sizeof(SchPuschInfo));
935          }
936          SCH_FREE(cellCb->schUlSlotInfo[slotIdx], sizeof(SchUlSlotInfo));  
937       }
938       SCH_FREE(cellCb->schUlSlotInfo,  cellCb->numSlots * sizeof(SchUlSlotInfo*));
939    }
940
941    for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
942    {
943       if(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai)
944       {
945          for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
946          {
947             SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai));
948          }
949          SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices*sizeof(Snssai*));
950       }
951    }
952
953    for(uint16_t idx =0; idx<MAX_SFN; idx++)
954    {
955       list = &cellCb->pageCb.pageIndInfoRecord[idx];
956       node = list->first;
957       while(node)
958       {
959          next = node->next;
960          if(node->node)
961          {
962             tempNode = (SchPageInfo*)(node->node);
963             SCH_FREE(tempNode->pagePdu, tempNode->msgLen);
964             SCH_FREE(node->node,  sizeof(SchPageInfo));
965          }
966          deleteNodeFromLList(list, node);
967          node = next;
968       }
969    }
970
971    cellCb->api->SchCellDeleteReq(cellCb);
972
973    memset(cellCb, 0, sizeof(SchCellCb));
974 }
975
976 /*******************************************************************
977  *
978  * @brief Function for cell Delete request from MAC to SCH
979  *
980  * @details
981  *
982  *    Function : SchProcCellDeleteReq
983  *
984  *    Functionality: Function for cell Delete request from MAC to SCH
985  *
986  * @params[in] Pst *pst, SchCellDelete  *cellDelete
987  * @return ROK     - success
988  *         RFAILED - failure
989  *
990  * ****************************************************************/
991 uint8_t SchProcCellDeleteReq(Pst *pst, SchCellDeleteReq  *cellDelete)
992 {
993    uint8_t   cellIdx=0, ret = RFAILED;
994    Inst      inst = pst->dstInst - SCH_INST_START;
995    SchMacRsp result= RSP_OK;
996    
997    if(!cellDelete)
998    {
999       DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): Ue Delete request failed");
1000    }
1001    else
1002    {
1003       GET_CELL_IDX(cellDelete->cellId, cellIdx);
1004       if(schCb[inst].cells[cellIdx] == NULLP)
1005       { 
1006          DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): cell Id[%d] is not available", cellDelete->cellId);
1007          result = RSP_NOK;
1008       }
1009       else
1010       {
1011          if(schCb[inst].cells[cellIdx]->cellId == cellDelete->cellId)
1012          {
1013             deleteSchCellCb(schCb[inst].cells[cellIdx]);
1014             result = RSP_OK;
1015             ret = ROK;
1016             SCH_FREE(schCb[inst].cells[cellIdx], sizeof(SchCellCb));
1017             DU_LOG("\nINFO   -->  SCH : Sending Cell Delete response to MAC");
1018          }
1019          else
1020          {
1021             DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): cell Id[%d] is not available",cellDelete->cellId);
1022             result = RSP_NOK;
1023          }
1024       }
1025
1026       if(SchSendCellDeleteRspToMac(cellDelete, inst, result)!=ROK)
1027       {
1028          DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): failed to send Cell Delete response");
1029          ret =  RFAILED;
1030       }
1031    }
1032    return ret;   
1033 }
1034
1035 /*******************************************************************
1036  *
1037  * @brief Processes DL RLC BO info from MAC
1038  *
1039  * @details
1040  *
1041  *    Function : SchProcDlRlcBoInfo
1042  *
1043  *    Functionality:
1044  *       Processes DL RLC BO info from MAC
1045  *
1046  * @params[in] 
1047  * @return ROK     - success
1048  *         RFAILED - failure
1049  *
1050  * ****************************************************************/
1051 uint8_t SchProcDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
1052 {
1053    uint8_t  lcId = 0;
1054    uint16_t ueId = 0;
1055    bool isLcIdValid = false;
1056    SchUeCb *ueCb = NULLP;
1057    SchCellCb *cell = NULLP;
1058    Inst  inst = pst->dstInst-SCH_INST_START;   
1059
1060    DU_LOG("\nDEBUG  -->  SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
1061    cell = schCb[inst].cells[inst];
1062
1063    if(cell == NULLP)
1064    {
1065       DU_LOG("\nERROR  -->  SCH : SchProcDlRlcBoInfo(): Cell does not exists");
1066       return RFAILED;
1067    }
1068
1069    GET_UE_ID(dlBoInfo->crnti, ueId);
1070    ueCb = &cell->ueCb[ueId-1];
1071    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1072    {
1073       DU_LOG("INFO  --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1074       return ROK;
1075    }
1076    
1077    lcId  = dlBoInfo->lcId;
1078    CHECK_LCID(lcId, isLcIdValid);
1079    if(isLcIdValid == FALSE)
1080    {
1081       DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
1082       return RFAILED;
1083    }
1084
1085    /*Expected when theres a case of Retransmission Failure or Resetablishment
1086     *By Zero BO, the RLC is informing that previous data can be cleared out
1087     *Thus clearing out the LC from the Lc priority list*/
1088    if(dlBoInfo->dataVolume == 0)
1089    {
1090       /* TODO : Check the LC is Dedicated or default and accordingly LCList
1091        * will be used*/
1092       return ROK;
1093    }
1094
1095    if(lcId == SRB0_LCID)
1096    {
1097       cell->raCb[ueId -1].msg4recvd = true;
1098       cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;      
1099    }
1100    else
1101    {
1102       /* TODO : These part of changes will be corrected during DL scheduling as
1103        * per K0 - K1 -K2 */
1104       SET_ONE_BIT(ueId, cell->boIndBitMap);
1105       if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1106       {
1107          ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1108       }
1109       else
1110       {
1111          DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1112          return RFAILED;
1113       }
1114    }
1115    /* Adding UE Id to list of pending UEs to be scheduled */
1116    cell->api->SchDlRlcBoInfo(cell, ueId);
1117    return ROK;
1118 }
1119
1120 /*******************************************************************
1121  *
1122  * @brief Processes BSR indiation from MAC
1123  *
1124  * @details
1125  *
1126  *    Function : SchProcBsr
1127  *
1128  *    Functionality:
1129  *       Processes DL BSR from MAC
1130  *
1131  * @params[in]    Pst pst
1132  *                UlBufferStatusRptInd bsrInd
1133  * @return ROK     - success
1134  *         RFAILED - failure
1135  *
1136  * ****************************************************************/
1137 uint8_t SchProcBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1138 {
1139    Inst           schInst       = pst->dstInst-SCH_INST_START;
1140    SchCellCb      *cellCb       = NULLP;
1141    SchUeCb        *ueCb         = NULLP;
1142    uint8_t        lcgIdx = 0;
1143
1144    DU_LOG("\nDEBUG  -->  SCH : Received BSR");
1145    if(bsrInd == NULLP)
1146    {
1147       DU_LOG("\nERROR  -->  SCH : BSR Ind is empty");
1148       return RFAILED;
1149    }
1150    cellCb = schCb[schInst].cells[schInst];
1151    if(cellCb == NULLP)
1152    {
1153       DU_LOG("\nERROR  -->  SCH : CellCb is empty");
1154       return RFAILED;
1155    }
1156    ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1157
1158    if(ueCb == NULLP)
1159    {
1160       DU_LOG("\nERROR  -->  SCH : UeCB is empty");
1161       return RFAILED;
1162    }
1163
1164    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1165    {
1166       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1167       return ROK;
1168    }
1169    
1170    ueCb->bsrRcvd = true;
1171    /* store dataVolume per lcg in uecb */
1172    for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1173    {
1174       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1175       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1176    }
1177    
1178    /* Adding UE Id to list of pending UEs to be scheduled */
1179    cellCb->api->SchBsr(cellCb, ueCb->ueId);
1180    return ROK;
1181 }
1182
1183 /*******************************************************************
1184  *
1185  * @brief Processes SR UCI indication from MAC 
1186  *
1187  * @details
1188  *
1189  *    Function : SchProcSrUciInd
1190  *
1191  *    Functionality:
1192  *      Processes SR UCI indication from MAC
1193  *
1194  * @params[in] Post structure
1195  *             UCI Indication
1196  * @return ROK     - success
1197  *         RFAILED - failure
1198  *
1199  * ****************************************************************/
1200 uint8_t SchProcSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1201 {
1202    Inst  inst = pst->dstInst-SCH_INST_START;
1203
1204    SchUeCb   *ueCb; 
1205    SchCellCb *cellCb = schCb[inst].cells[inst];
1206
1207    DU_LOG("\nDEBUG  -->  SCH : Received SR");
1208
1209    ueCb = schGetUeCb(cellCb, uciInd->crnti);
1210    
1211    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1212    {
1213       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
1214       return ROK;  
1215    }
1216    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1217    {
1218       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1219       return ROK;
1220    }
1221    if(uciInd->numSrBits)
1222    {
1223       ueCb->srRcvd = true;      
1224       /* Adding UE Id to list of pending UEs to be scheduled */
1225       cellCb->api->SchSrUciInd(cellCb, ueCb->ueId);
1226    }
1227    return ROK;
1228 }
1229
1230 /*******************************************************************
1231  *
1232  * @brief Processes DL HARQ indication from MAC 
1233  *
1234  * @details
1235  *
1236  *    Function : SchProcDlHarqInd
1237  *
1238  *    Functionality:
1239  *      Processes DL HARQ indication from MAC
1240  *
1241  * @params[in] Post structure
1242  *             DL HARQ Indication
1243  * @return ROK     - success
1244  *         RFAILED - failure
1245  *
1246  * ****************************************************************/
1247 uint8_t SchProcDlHarqInd(Pst *pst, DlHarqInd *dlHarqInd)
1248 {
1249    Inst  inst = pst->dstInst-SCH_INST_START;
1250    SchUeCb   *ueCb;
1251    SchCellCb *cellCb = schCb[inst].cells[inst];
1252
1253    DU_LOG("\nDEBUG  -->  SCH : Received HARQ");
1254
1255    ueCb = schGetUeCb(cellCb, dlHarqInd->crnti);
1256
1257    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1258    {
1259       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", dlHarqInd->crnti);
1260       return ROK;
1261    }
1262
1263    schUpdateHarqFdbk(ueCb, dlHarqInd->numHarq, dlHarqInd->harqPayload, &dlHarqInd->slotInd);
1264
1265    return ROK;
1266 }
1267
1268 /*******************************************************************
1269  *
1270  * @brief Allocates requested PRBs for DL
1271  *
1272  * @details
1273  *
1274  *    Function : allocatePrbDl
1275  *
1276  *    Functionality:
1277  *      Allocates requested PRBs in DL
1278  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1279  *
1280  * @params[in] prbAlloc table
1281  *             Start symbol
1282  *             Number of symbols
1283  *             Start PRB
1284  *             Number of PRBs
1285  *
1286  * @return ROK     - success
1287  *         RFAILED - failure
1288  *
1289  * ****************************************************************/
1290 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1291    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1292 {
1293    uint8_t        symbol = 0;
1294    uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0;
1295    FreePrbBlock   *freePrbBlock = NULLP;
1296    CmLList        *freePrbNode = NULLP;
1297    PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1298    SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1299    SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
1300
1301    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1302     * Search for an appropriate location in PRB grid and allocate requested resources */
1303    if(*startPrb == MAX_NUM_RB)
1304    {
1305       /* Check if SSB/SIB1 is also scheduled in this slot  */
1306       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1307       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1308
1309       if(ssbOccasion && sib1Occasion)
1310       {
1311          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
1312          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1313       }
1314       else if(ssbOccasion)
1315       {
1316          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1317          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1318       }
1319       else if(sib1Occasion)
1320       {
1321          broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1322          broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1323       }
1324
1325       /* Iterate through all free PRB blocks */
1326       freePrbNode = prbAlloc->freePrbBlockList.first; 
1327       while(freePrbNode)
1328       {
1329          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1330
1331          /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1332           * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1333          if((ssbOccasion || sib1Occasion) && 
1334             ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1335             ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1336          {
1337             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1338             if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1339             {
1340                /* If sufficient free PRBs are available above bradcast message then,
1341                 * endPrb = freePrbBlock->endPrb
1342                 * startPrb = endPrb - numPrb +1;
1343                 */
1344                *startPrb = freePrbBlock->endPrb - numPrb +1;
1345                break;
1346             }
1347             else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1348             {
1349                /* If free PRBs are available below broadcast message then,
1350                 * endPrb = broadcastPrbStart - 1
1351                 * startPrb = endPrb - numPrb +1
1352                 */
1353                *startPrb = broadcastPrbStart - numPrb; 
1354                break;
1355             }
1356             else
1357             {
1358                freePrbNode = freePrbNode->next;
1359                continue;
1360             }
1361          }
1362          else
1363          {
1364             /* Check if requested number of blocks can be allocated from the current block */ 
1365             if (freePrbBlock->numFreePrb < numPrb)
1366             {
1367                freePrbNode = freePrbNode->next;
1368                continue;
1369             }
1370             *startPrb = freePrbBlock->endPrb - numPrb +1;
1371             break;  
1372          }
1373       }
1374
1375       /* If no free block can be used to allocated request number of RBs */
1376       if(*startPrb == MAX_NUM_RB)
1377          return RFAILED;
1378    }
1379
1380    /* If startPrb is known already, check if requested PRBs are available for allocation */
1381    else
1382    {
1383       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1384       if(!freePrbNode)
1385       {
1386          DU_LOG("\nERROR  -->  SCH: Requested DL PRB unavailable");
1387          return RFAILED;
1388       }
1389    }
1390
1391    /* Update bitmap to allocate PRBs */
1392    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1393    {
1394       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1395       {
1396          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1397          return RFAILED;
1398       }
1399    }
1400    
1401    /* Update statistics of PRB usage if stats calculation is enabled */
1402    if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
1403       prbAlloc->numPrbAlloc += numPrb;
1404
1405    /* Update the remaining number for free PRBs */
1406    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1407
1408    return ROK;
1409 }
1410
1411 /*******************************************************************
1412  *
1413  * @brief Allocates requested PRBs for UL
1414  *
1415  * @details
1416  *
1417  *    Function : allocatePrbUl
1418  *
1419  *    Functionality:
1420  *      Allocates requested PRBs in UL
1421  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1422  *
1423  * @params[in] prbAlloc table
1424  *             Start symbol
1425  *             Number of symbols
1426  *             Start PRB
1427  *             Number of PRBs
1428  *
1429  * @return ROK     - success
1430  *         RFAILED - failure
1431  *
1432  * ****************************************************************/
1433 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1434    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1435 {
1436    uint8_t        symbol = 0;
1437    uint16_t       prachStartPrb, prachNumPrb, prachEndPrb;
1438    bool           isPrachOccasion;
1439    FreePrbBlock   *freePrbBlock = NULLP;
1440    CmLList        *freePrbNode = NULLP;
1441    SchPrbAlloc    *prbAlloc = NULLP;
1442
1443    if(cell == NULLP)
1444    {
1445       DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
1446       return RFAILED;
1447    }
1448    
1449    prbAlloc =   &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1450    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1451     * Search for an appropriate location in PRB grid and allocate requested resources */
1452    if(*startPrb == MAX_NUM_RB)
1453    {
1454       /* Check if PRACH is also scheduled in this slot */
1455       isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1456       if(isPrachOccasion)
1457       {
1458          prachStartPrb =  cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1459          prachNumPrb = schCalcPrachNumRb(cell);
1460          prachEndPrb = prachStartPrb + prachNumPrb -1;
1461       }
1462
1463       /* Iterate through all free PRB blocks */
1464       freePrbNode = prbAlloc->freePrbBlockList.first; 
1465       while(freePrbNode)
1466       {
1467          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1468
1469          /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1470           * PRBs required for PRACH cannot be allocated to any other message */
1471          if((isPrachOccasion) &&
1472             ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1473             ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1474          {
1475             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1476             if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1477             {
1478                /* If sufficient free PRBs are available above PRACH message then,
1479                 * endPrb = freePrbBlock->endPrb
1480                 * startPrb = endPrb - numPrb +1;
1481                 */
1482                *startPrb = freePrbBlock->endPrb - numPrb +1;
1483                break;
1484             }
1485             else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1486             {
1487                /* If free PRBs are available below PRACH message then,
1488                 * endPrb = prachStartPrb - 1
1489                 * startPrb = endPrb - numPrb +1
1490                 */
1491                *startPrb = prachStartPrb - numPrb; 
1492                break;
1493             }
1494             else
1495             {
1496                freePrbNode = freePrbNode->next;
1497                continue;
1498             } 
1499          }
1500          else
1501          {
1502             /* Check if requested number of PRBs can be allocated from currect block */
1503             if(freePrbBlock->numFreePrb < numPrb)
1504             {
1505                freePrbNode = freePrbNode->next;
1506                continue;
1507             }
1508             *startPrb = freePrbBlock->endPrb - numPrb +1;
1509             break;
1510          }
1511       }
1512
1513       /* If no free block can be used to allocated requested number of RBs */
1514       if(*startPrb == MAX_NUM_RB)
1515          return RFAILED;
1516    }
1517    else
1518    {
1519       /* If startPrb is known already, check if requested PRBs are available for allocation */
1520       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1521       if(!freePrbNode)
1522       {
1523          DU_LOG("\nERROR  -->  SCH: Requested UL PRB unavailable");
1524          return RFAILED;
1525       }
1526    }
1527
1528    /* Update bitmap to allocate PRBs */
1529    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1530    {
1531       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1532       {
1533          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1534          return RFAILED;
1535       }
1536    }
1537
1538    /* Update statistics of PRB usage if stats calculation is enabled */
1539    if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
1540       prbAlloc->numPrbAlloc += numPrb;
1541
1542    /* Update the remaining number for free PRBs */
1543    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1544
1545    return ROK;
1546 }
1547
1548 /*******************************************************************************
1549  *
1550  * @brief Try to find Best Free Block with Max Num PRB 
1551  *
1552  * @details
1553  *
1554  *    Function : searchLargestFreeBlock
1555  *
1556  *    Functionality:
1557  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1558  *
1559  * @params[in] I/P > prbAlloc table (FreeBlock list)
1560  *             I/P > Slot timing Info
1561  *             O/P > Start PRB
1562  *             I/P > Direction (UL/DL)
1563  *       
1564  *
1565  * @return Max Number of Free PRB 
1566  *         If 0, then no Suitable Free Block
1567  *
1568  * ********************************************************************************/
1569
1570 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1571 {
1572    uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1573    FreePrbBlock   *freePrbBlock = NULLP;
1574    CmLList        *freePrbNode = NULLP;
1575    SchPrbAlloc    *prbAlloc = NULLP;
1576    bool           checkOccasion = FALSE;
1577
1578    *startPrb = 0; /*Initialize the StartPRB to zero*/
1579
1580    /*Based on Direction, Reserved Messsages will differi.e.
1581     * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1582     * and reserved before allocation for dedicated DL/UL msg*/
1583    if(dir == DIR_DL)
1584    {
1585       SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1586       PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1587
1588       prbAlloc = &schDlSlotInfo->prbAlloc;
1589
1590       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1591       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1592
1593       checkOccasion = TRUE;
1594       if(ssbOccasion && sib1Occasion)
1595       {
1596          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
1597          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1598                           cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1599       }
1600       else if(ssbOccasion)
1601       {
1602          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1603          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1604       }
1605       else if(sib1Occasion)
1606       {
1607          reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1608          reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1609       }
1610       else
1611       {
1612          checkOccasion = FALSE;  
1613       }
1614    }
1615    else if(dir == DIR_UL)
1616    {
1617       prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1618
1619       /* Check if PRACH is also scheduled in this slot */
1620       checkOccasion = schCheckPrachOcc(cell, slotTime);
1621       if(checkOccasion)
1622       {
1623          reservedPrbStart =  cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1624          reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1625       }
1626    }
1627    else
1628    {
1629       DU_LOG("\nERROR --> SCH: Invalid Direction!");
1630       return (maxFreePRB);
1631    }
1632
1633    freePrbNode = prbAlloc->freePrbBlockList.first; 
1634    while(freePrbNode)
1635    {
1636       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1637
1638       /*For block with same numFreeBlocks, choose the one with HighestPRB range
1639        *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1640       if(maxFreePRB >= freePrbBlock->numFreePrb) 
1641       {
1642          //skip this block
1643          freePrbNode = freePrbNode->next;
1644          continue;
1645       }
1646
1647       /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1648        * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1649       if(checkOccasion && 
1650             ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1651             ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1652       {
1653
1654          /* Implmentation is done such that highest-numbered free-RB is Checked first
1655             and freePRB in this block is greater than Max till now */
1656          if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1657          {
1658             /* If sufficient free PRBs are available above reserved message*/
1659             *startPrb = reservedPrbEnd + 1;
1660             maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);                
1661          }
1662          /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1663          if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1664          {
1665             /* If free PRBs are available below reserved message*/
1666             *startPrb = freePrbBlock->startPrb;
1667             maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1668          }
1669       }
1670       else  //Best Block
1671       {
1672          if(maxFreePRB < freePrbBlock->numFreePrb)
1673          {
1674             *startPrb = freePrbBlock->startPrb;
1675             maxFreePRB = freePrbBlock->numFreePrb;
1676          }
1677
1678       }
1679       freePrbNode = freePrbNode->next;
1680    }  
1681    return(maxFreePRB);
1682 }
1683
1684 /*******************************************************************************
1685  *
1686  * @brief This function is used to send Slice Cfg rsp to MAC
1687  *
1688  * @details
1689  *
1690  *    Function : SchSendSliceCfgRspToMac
1691  *
1692  *    Functionality:
1693  *     function is used to send Slice Cfg rsp to MAC
1694  *
1695  * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1696  *
1697  * @return- void
1698  *
1699  * ********************************************************************************/
1700 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1701 {
1702    Pst rspPst;
1703    
1704    memset(&rspPst, 0, sizeof(Pst));
1705    FILL_PST_SCH_TO_MAC(rspPst, inst);
1706    rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1707    
1708    MacMessageRouter(&rspPst, (void *)&sliceCfgRsp);
1709
1710 }
1711
1712 /*******************************************************************************
1713  *
1714  * @brief This function is used to store or modify the slice configuration Sch DB
1715  *
1716  * @details
1717  *
1718  *    Function : addOrModifySliceCfgInSchDb 
1719  *
1720  *    Functionality:
1721  *     function is used to store or modify the slice configuration Sch DB
1722  *
1723  * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1724  * SchSliceCfgRsp cfgRsp, uint8_t count
1725  *
1726  * @return
1727  *        ROK - Success
1728  *        RFAILED - Failure
1729  *
1730  * ********************************************************************************/
1731 uint8_t addSliceCfgInSchDb(CmLListCp *sliceCfgInDb, SchRrmPolicyOfSlice *cfgReq)
1732 {
1733    SchRrmPolicyOfSlice *sliceToStore;
1734
1735    SCH_ALLOC(sliceToStore, sizeof(SchRrmPolicyOfSlice));
1736    if(sliceToStore)
1737    {
1738       memcpy(&sliceToStore->snssai, &cfgReq->snssai, sizeof(Snssai));  
1739       memcpy(&sliceToStore->rrmPolicyRatioInfo, &cfgReq->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));  
1740       addNodeToLList(sliceCfgInDb, sliceToStore, NULL);
1741    }
1742    else
1743    {
1744       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in addOrModifySliceCfgInSchDb");
1745       return RFAILED;
1746    }
1747    return ROK;
1748 }
1749
1750 /*******************************************************************************
1751  *
1752  * @brief fill slice configuration response
1753  *
1754  * @details
1755  *
1756  *    Function : fillSliceCfgRsp
1757  *
1758  *    Functionality:
1759  *     fill slice configuration response
1760  *
1761  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1762  *
1763  * @return
1764  *        ROK - Success
1765  *        RFAILED - Failure
1766  *
1767  * ********************************************************************************/
1768 uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq)
1769 {
1770    SchMacRsp sliceFound;
1771    uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0, ret =ROK;
1772    SchSliceCfgRsp schSliceCfgRsp;
1773
1774    for(cfgIdx = 0; cfgIdx<schSliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1775    {
1776       sliceFound = RSP_NOK;
1777       /* Here comparing the slice cfg request with the slice stored in cellCfg */
1778       for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
1779       {
1780          for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
1781          {
1782             /* 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. */ 
1783             if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai)))
1784             {
1785                if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
1786                {
1787                   sliceFound = RSP_OK;
1788                   schSliceCfgRsp.cause = SUCCESSFUL;
1789                }
1790                else
1791                {
1792                   DU_LOG("\nERROR  --> SCH : Failed to store slice configuration in SchDb");
1793                   schSliceCfgRsp.cause = RESOURCE_UNAVAILABLE;
1794                   ret = RFAILED;
1795                }
1796                plmnIdx = MAX_PLMN;
1797                break;
1798             }
1799          }
1800       }
1801       
1802       if((sliceFound == RSP_NOK) && (schSliceCfgRsp.cause != RESOURCE_UNAVAILABLE))
1803          schSliceCfgRsp.cause = SLICE_NOT_FOUND;
1804       
1805       schSliceCfgRsp.snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
1806       schSliceCfgRsp.rsp    = sliceFound;
1807       SchSendSliceCfgRspToMac(inst, schSliceCfgRsp);
1808    }
1809    return ret;
1810 }
1811
1812 /*******************************************************************************
1813  *
1814  * @brief This function is used to free the slice cfg and re cfg request pointer
1815  *
1816  * @details
1817  *
1818  *    Function : freeSchSliceCfgReq 
1819  *
1820  *    Functionality:
1821  *     function is used to free the slice cfg and re cfg request pointer
1822  *
1823  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1824  *
1825  * @return
1826  *        ROK - Success
1827  *        RFAILED - Failure
1828  * ********************************************************************************/
1829 void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
1830 {
1831    uint8_t cfgIdx = 0;
1832    
1833    if(sliceCfgReq)
1834    {
1835       if(sliceCfgReq->numOfConfiguredSlice)
1836       {
1837          for(cfgIdx = 0; cfgIdx<sliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1838          {
1839             if(sliceCfgReq->listOfSlices[cfgIdx])
1840             {
1841                SCH_FREE(sliceCfgReq->listOfSlices[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1842             }
1843          }
1844          SCH_FREE(sliceCfgReq->listOfSlices, sliceCfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1845       }
1846       SCH_FREE(sliceCfgReq, sizeof(SchSliceCfgReq));
1847    }
1848 }
1849 /*******************************************************************************
1850  *
1851  * @brief This function is used to store the slice configuration Sch DB
1852  *
1853  * @details
1854  *
1855  *    Function : SchProcSliceCfgReq 
1856  *
1857  *    Functionality:
1858  *     function is used to store the slice configuration Sch DB
1859  *
1860  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1861  *
1862  * @return
1863  *        ROK - Success
1864  *        RFAILED - Failure
1865  *
1866  * ********************************************************************************/
1867 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1868 {
1869    uint8_t ret = ROK;
1870    Inst   inst = pst->dstInst - SCH_INST_START;
1871
1872    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
1873    if(schSliceCfgReq)
1874    {
1875       if(schSliceCfgReq->listOfSlices)
1876       {
1877          /* filling the slice configuration response of each slice */
1878          if(fillSliceCfgRsp(inst, &schCb[inst].sliceCfg, schCb[inst].cells[0], schSliceCfgReq) != ROK)
1879          {
1880             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
1881             ret = RFAILED;
1882          }
1883          freeSchSliceCfgReq(schSliceCfgReq);
1884       }
1885    }
1886    else
1887    {
1888       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1889       ret = RFAILED;
1890    }
1891    return ret;
1892 }
1893
1894 /*******************************************************************************
1895  *
1896  * @brief This function is used to send Slice re Cfg rsp to MAC
1897  *
1898  * @details
1899  *
1900  *    Function : SchSendSliceRecfgRspToMac
1901  *
1902  *    Functionality:
1903  *     function is used to send Slice re Cfg rsp to MAC
1904  *
1905  * @params[in] Pst *pst, SchSliceRecfgRsp schSliceRecfgRsp
1906  *
1907  * @return- void
1908  *
1909  * ********************************************************************************/
1910 void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
1911 {
1912    Pst rspPst;
1913    
1914    memset(&rspPst, 0, sizeof(Pst));
1915    FILL_PST_SCH_TO_MAC(rspPst, inst);
1916    rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1917    
1918    MacMessageRouter(&rspPst, (void *)&schSliceRecfgRsp);
1919 }
1920
1921 /*******************************************************************************
1922  *
1923  * @brief fill slice configuration response
1924  *
1925  * @details
1926  *
1927  *    Function : fillSliceRecfgRsp
1928  *
1929  *    Functionality: fill slice reconfiguration response
1930  *
1931  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1932  *
1933  * @return
1934  *        ROK - Success
1935  *        RFAILED - Failure
1936  *
1937  * ********************************************************************************/
1938
1939 uint8_t fillSliceRecfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchSliceRecfgReq *schSliceRecfgReq)
1940 {
1941    SchMacRsp sliceFound;
1942    uint8_t cfgIdx = 0;
1943    SchRrmPolicyOfSlice *rrmPolicyOfSlices;
1944    SchSliceRecfgRsp schSliceRecfgRsp;
1945
1946    for(cfgIdx = 0; cfgIdx<schSliceRecfgReq->numOfConfiguredSlice; cfgIdx++)
1947    {
1948       sliceFound = RSP_NOK;
1949       /* Here comparing the slice recfg request with the StoredSliceCfg */
1950       CmLList *sliceCfg = storedSliceCfg->first;
1951
1952       while(sliceCfg)
1953       {
1954          rrmPolicyOfSlices = (SchRrmPolicyOfSlice*)sliceCfg->node;
1955          
1956          if(rrmPolicyOfSlices && (memcmp(&schSliceRecfgReq->listOfSlices[cfgIdx]->snssai, &(rrmPolicyOfSlices->snssai), sizeof(Snssai)) == 0))
1957          {
1958             memcpy(&rrmPolicyOfSlices->rrmPolicyRatioInfo, &schSliceRecfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1959             sliceFound = RSP_OK;
1960             break;
1961          }
1962          sliceCfg = sliceCfg->next;
1963       }
1964
1965       schSliceRecfgRsp.snssai = schSliceRecfgReq->listOfSlices[cfgIdx]->snssai;
1966       schSliceRecfgRsp.rsp    = sliceFound;
1967       if(schSliceRecfgRsp.rsp == RSP_OK)
1968          schSliceRecfgRsp.cause = SUCCESSFUL;
1969       else
1970          schSliceRecfgRsp.cause = SLICE_NOT_FOUND;
1971       SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
1972    }
1973    return ROK;
1974 }
1975 /*******************************************************************************
1976  *
1977  * @brief This function is used to store the slice reconfiguration Sch DB
1978  *
1979  * @details
1980  *
1981  *    Function : SchProcSliceRecfgReq 
1982  *
1983  *    Functionality:
1984  *     function is used to store the slice re configuration Sch DB
1985  *
1986  * @params[in] Pst *pst, SchSliceRecfgReq *schSliceRecfgReq
1987  *
1988  * @return
1989  *        ROK - Success
1990  *        RFAILED - Failure
1991  *
1992  * ********************************************************************************/
1993 uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
1994 {
1995    uint8_t ret = ROK;
1996    Inst   inst = pst->dstInst - SCH_INST_START;
1997
1998    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
1999    if(schSliceRecfgReq)
2000    {
2001       if(schSliceRecfgReq->listOfSlices)
2002       {
2003          /* filling the slice configuration response of each slice */
2004          if(fillSliceRecfgRsp(inst, &schCb[inst].sliceCfg, schSliceRecfgReq) != ROK)
2005          {
2006             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
2007             ret = RFAILED;
2008          }
2009          freeSchSliceCfgReq(schSliceRecfgReq);
2010       }
2011    }
2012    else
2013    {
2014       DU_LOG("\nERROR  -->  SCH : Received SchSliceRecfgReq is NULL");
2015
2016    }
2017    return ret;
2018 }
2019
2020 /****************************************************************************
2021  *
2022  * @brief Stores the Paging Configuration from DU APP in CellCb 
2023  *
2024  * @details
2025  *
2026  *    Function : schProcPagingParam
2027  *
2028  *    Functionality:
2029  *          Process the Paging Configuration when FirstPDCCHMonitoring for
2030  *          Paging Ocassion is not present.
2031  *
2032  *          As per 38.304 Sec 7.1,
2033  *          "When firstPDCCH-MonitoringOccasionOfPO is present, the
2034  *          starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2035  *          (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2036  *          parameter; otherwise, it is equal to i_s * S."
2037  *          "S = number of actual transmitted SSBs determined according 
2038  *              to ssb-PositionsInBurst in SIB1"
2039  *
2040  * @params[in] SchCellCb *cell 
2041  *       
2042  * @return void 
2043  *        
2044  *************************************************************************/
2045 void schProcPagingCfg(SchCellCb *cell)
2046 {
2047    SchPcchCfg *pageCfgRcvd = NULL;
2048    uint8_t i_sIdx = 0;
2049
2050    pageCfgRcvd = &(cell->cellCfg.dlCfgCommon.schPcchCfg);
2051
2052    if(pageCfgRcvd->poPresent == TRUE)
2053    {
2054       /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2055       for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2056       {
2057          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2058          if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2059          {
2060             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2061          }
2062
2063          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2064
2065       }
2066    }
2067    else
2068    {
2069       schCfgPdcchMonOccOfPO(cell);                  
2070    }
2071 }
2072
2073 /****************************************************************************
2074  *
2075  * @brief Calculate PO if not present in Configuration 
2076  *
2077  * @details
2078  *
2079  *    Function : schCfgPdcchMonOccOfPO
2080  *
2081  *    Functionality: In this function, PO are calculated i_s * S because
2082  *    FirstPDCCHMonitoring_ForPO is not present.
2083  *
2084  * @params[in] SchCellCb *cellCb
2085  *       
2086  * @return void 
2087  *        
2088  *************************************************************************/
2089 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2090 {
2091    uint8_t         cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2092    uint8_t         nsValue = cell->cellCfg.dlCfgCommon.schPcchCfg.numPO;
2093    uint8_t         totalNumSsb = countSetBits(cell->cellCfg.ssbPosInBurst[0]);
2094    SlotTimingInfo  tmpTimingInfo, pdcchTime; 
2095
2096    /*Starting with First Sfn and slot*/
2097    tmpTimingInfo.sfn = 0;
2098    tmpTimingInfo.slot = 0;
2099
2100    pdcchTime = tmpTimingInfo;
2101
2102    while(i_sIdx < nsValue)
2103    {
2104       /*Increment frame Offset if PO falls on next SFN*/
2105       if(pdcchTime.sfn != tmpTimingInfo.sfn)
2106       {
2107          frameOffSet++;
2108       }
2109       pdcchTime = tmpTimingInfo;
2110       schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2111
2112       if (i_sIdx == 0)
2113       {
2114          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2115          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2116          i_sIdx++;
2117       }
2118       else
2119       {
2120          cnt++;
2121          if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF)) 
2122          {
2123             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2124             cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2125             cnt = 0;
2126             i_sIdx++;
2127          }
2128       }
2129    }
2130 }
2131
2132 /****************************************************************************
2133  *
2134  * @brief Storing the paging information in SCH database 
2135  *
2136  * @details
2137  *
2138  *    Function : schAddPagingIndtoList
2139  *
2140  *    Functionality: Storing the paging information in SCH database
2141  *
2142  * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2143  *       
2144  * @return ROK - sucess
2145  *         RFAILED - failure
2146  *        
2147  *************************************************************************/
2148 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2149 {
2150    CmLList  *firstNodeOfList = NULLP;
2151    CmLList  *currentNodeInfo = NULLP;
2152    SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2153    
2154    recvdNode = (SchPageInfo*) pageIndInfo;
2155    CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2156    
2157    SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2158    if(!currentNodeInfo)
2159    {  
2160       DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2161       return RFAILED;
2162    }
2163    
2164    currentNodeInfo->node = (PTR)pageIndInfo;
2165    while(firstNodeOfList)
2166    {
2167       tempNode = (SchPageInfo*)(firstNodeOfList->node);
2168       if ((recvdNode->pageTxTime.slot < tempNode->pageTxTime.slot))
2169       {
2170          cmLListInsCrnt(storedPageList, currentNodeInfo);
2171          break;
2172       }
2173       else if ((recvdNode->pageTxTime.slot == tempNode->pageTxTime.slot))
2174       {
2175          DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->pageTxTime.slot);
2176          return RFAILED;
2177       }
2178       else
2179       {
2180          CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2181       }
2182    } 
2183    
2184    if(!firstNodeOfList)
2185    {
2186       cmLListAdd2Tail(storedPageList, currentNodeInfo);
2187    }
2188    DU_LOG("\nDEBUG   -->  SCH : Paging information is stored successfully for PF:%d, Slot:%d",\
2189               recvdNode->pageTxTime.sfn, recvdNode->pageTxTime.slot);
2190    return ROK;
2191 }
2192
2193 /****************************************************************************
2194  *
2195  * @brief Process paging indication at  SCH recevied form MAC 
2196  *
2197  * @details
2198  *
2199  *    Function : SchProcPagingInd
2200  *
2201  *    Functionality: Process paging indication at SCH recevied form MAC 
2202  *
2203  * @params[in] Pst *pst,  SchPageInd *pageInd 
2204  *       
2205  * @return void 
2206  *        
2207  *************************************************************************/
2208 uint8_t SchProcPagingInd(Pst *pst,  SchPageInd *pageInd)
2209 {
2210    uint8_t ret = RFAILED;
2211    uint16_t cellIdx = 0;
2212    Inst  inst = pst->dstInst - SCH_INST_START;
2213    SchCellCb *cellCb = NULLP;
2214    SchPageInfo *pageInfo = NULLP;
2215
2216    if(pageInd)
2217    {
2218       DU_LOG("\nDEBUG   -->  SCH : Received paging indication from MAC for cellId[%d]",\
2219                   pageInd->cellId);
2220
2221       /* Fetch Cell CB */
2222       for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2223       {
2224          if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2225          {
2226             cellCb = schCb[inst].cells[cellIdx];
2227             break;
2228          }
2229       }
2230       if(cellCb)
2231       {
2232          if(pageInd->i_s > cellCb->cellCfg.dlCfgCommon.schPcchCfg.numPO)
2233          {
2234             DU_LOG("\nERROR --> SCH : SchProcPagingInd(): i_s should not be greater than number of paging occasion");
2235          }
2236          else
2237          {
2238             SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2239             if(pageInfo)
2240             {
2241                pageInfo->pf = pageInd->pf; 
2242                pageInfo->i_s = pageInd->i_s;
2243                pageInfo->pageTxTime.cellId = pageInd->cellId;
2244                pageInfo->pageTxTime.sfn = (pageInd->pf +  cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2245                pageInfo->pageTxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2246                pageInfo->mcs = DEFAULT_MCS;
2247                pageInfo->msgLen =  pageInd->pduLen;
2248                SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2249                if(!pageInfo->pagePdu)
2250                {
2251                   DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to allocate memory");
2252                }
2253                else
2254                {
2255                   memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2256                   ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->pageTxTime.sfn], pageInfo);
2257                   if(ret != ROK)
2258                   {
2259                      DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to store paging record");
2260                   }
2261                }
2262             }
2263             else
2264             {
2265                DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to allocate memory");
2266             }
2267          }
2268       }
2269       else
2270       {
2271          DU_LOG("\nERROR  -->  SCH : Cell ID [%d] not found", pageInd->cellId);
2272       }
2273       SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2274       SCH_FREE(pageInd, sizeof(SchPageInd));
2275    }
2276    else
2277    {
2278       DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Received null pointer");
2279    }
2280    return ret;
2281 }
2282
2283 \f
2284 /***********************************************************
2285  *
2286  *     Func : SchFillCfmPst 
2287  *        
2288  *
2289  *     Desc : Fills the Confirmation Post Structure cfmPst using the reqPst 
2290  *            and the cfm->hdr.response.
2291  *            
2292  *
2293  *     Ret  : Void
2294  *
2295  *     Notes: 
2296  *
2297  *     File : rg_sch_lmm.c 
2298  *
2299  **********************************************************/
2300 Void SchFillCfmPst
2301 (
2302 Pst           *reqPst,
2303 Pst           *cfmPst,
2304 RgMngmt       *cfm
2305 )
2306 {
2307    Inst inst;
2308
2309    inst = (reqPst->dstInst - SCH_INST_START);
2310
2311    cfmPst->srcEnt    = ENTMAC;
2312    cfmPst->srcInst   = (Inst) 1;
2313    cfmPst->srcProcId = schCb[inst].schInit.procId;
2314    cfmPst->dstEnt    = ENTMAC;
2315    cfmPst->dstInst   = (Inst) 0;
2316    cfmPst->dstProcId = reqPst->srcProcId;
2317
2318    cfmPst->selector  = cfm->hdr.response.selector;
2319    cfmPst->region    = cfm->hdr.response.mem.region;
2320    cfmPst->pool      = cfm->hdr.response.mem.pool;
2321
2322    return;
2323 }
2324
2325 /*******************************************************************
2326  *
2327  * @brief Processes DL CQI ind from MAC
2328  *
2329  * @details
2330  *
2331  *    Function : SchProcDlCqiInd
2332  *
2333  *    Functionality:
2334  *       Processes DL CQI ind from MAC
2335  *
2336  * @params[in] 
2337  * @return ROK     - success
2338  *         RFAILED - failure
2339  *
2340  * ****************************************************************/
2341 uint8_t SchProcDlCqiInd(Pst *pst, SchDlCqiInd *dlCqiInd)
2342 {
2343    uint8_t  ret = ROK;
2344    uint16_t ueId = 0, cellIdx = 0;
2345    SchUeCb *ueCb = NULLP;
2346    SchCellCb *cell = NULLP;
2347    Inst  inst = pst->dstInst-SCH_INST_START;   
2348
2349    if(!dlCqiInd)
2350    {
2351       DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): CQI Ind is empty");
2352       ret = RFAILED;
2353    }
2354    else
2355    {
2356       GET_CELL_IDX(dlCqiInd->cellId, cellIdx);
2357       cell = schCb[inst].cells[cellIdx];
2358       if(cell == NULLP)
2359       { 
2360          DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): cell Id[%d] not found", dlCqiInd->cellId);
2361          ret = RFAILED;
2362       }
2363       else
2364       {
2365          if(cell->cellId == dlCqiInd->cellId)
2366          {
2367             GET_UE_ID(dlCqiInd->crnti, ueId);
2368             ueCb = &cell->ueCb[ueId-1];
2369             if(ueCb->crnti != dlCqiInd->crnti)
2370             {
2371                DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): UeCb for received crnti[%d] not found", dlCqiInd->crnti);
2372                ret = RFAILED;
2373             }
2374             else
2375             {
2376                /*TODO: complete the processing of DL CQI Ind*/ 
2377             }
2378          }
2379          else
2380          {
2381             DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): Received cell Id[%d] from MAC is not matching with CellID[%d] in SCH Cb",\
2382                     dlCqiInd->cellId, cell->cellId);
2383             ret = RFAILED;
2384          }
2385       }
2386    }
2387    return ret;
2388 }
2389
2390 /*******************************************************************
2391  *
2392  * @brief Processes UL CQI ind from MAC
2393  *
2394  * @details
2395  *
2396  *    Function : SchProcUlCqiInd
2397  *
2398  *    Functionality:
2399  *       Processes UL CQI ind from MAC
2400  *
2401  * @params[in] 
2402  * @return ROK     - success
2403  *         RFAILED - failure
2404  *
2405  * ****************************************************************/
2406 uint8_t SchProcUlCqiInd(Pst *pst, SchUlCqiInd *ulCqiInd)
2407 {
2408    uint8_t  ret = ROK;
2409    uint16_t ueId = 0, cellIdx = 0;
2410    SchUeCb *ueCb = NULLP;
2411    SchCellCb *cell = NULLP;
2412    Inst  inst = pst->dstInst-SCH_INST_START;   
2413
2414    if(!ulCqiInd)
2415    {
2416       DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): CQI Ind is empty");
2417       ret = RFAILED;
2418    }
2419    else
2420    {
2421       GET_CELL_IDX(ulCqiInd->cellId, cellIdx);
2422       cell = schCb[inst].cells[cellIdx];
2423       if(cell == NULLP)
2424       { 
2425          DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): cell Id[%d] not found", ulCqiInd->cellId);
2426          ret = RFAILED;
2427       }
2428       else
2429       {
2430          if(cell->cellId == ulCqiInd->cellId)
2431          {
2432             GET_UE_ID(ulCqiInd->crnti, ueId);
2433             ueCb = &cell->ueCb[ueId-1];
2434             if(ueCb->crnti != ulCqiInd->crnti)
2435             {
2436                DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): UeCb for received crnti[%d] not found",ulCqiInd->crnti);
2437                ret = RFAILED;
2438             }
2439             else
2440             {
2441                /*TODO: complete the processing of UL CQI Ind*/ 
2442             }
2443          }
2444          else
2445          {
2446             DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): Received cell Id[%d] from MAC is not matching with CellId[%d] in SCH Cb",\
2447                     ulCqiInd->cellId, cell->cellId);
2448             ret = RFAILED;
2449          }
2450       }
2451    }
2452    return ret;
2453 }
2454
2455 /*******************************************************************
2456  *
2457  * @brief Processes PHR ind from MAC
2458  *
2459  * @details
2460  *
2461  *    Function : SchProcPhrInd
2462  *
2463  *    Functionality:
2464  *       Processes PHR ind from MAC
2465  *
2466  * @params[in] 
2467  * @return ROK     - success
2468  *         RFAILED - failure
2469  *
2470  * ****************************************************************/
2471 uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
2472 {
2473    uint8_t  ret = ROK;
2474    uint16_t ueId = 0, cellIdx = 0;
2475    SchUeCb *ueCb = NULLP;
2476    SchCellCb *cell = NULLP;
2477    Inst  inst = pst->dstInst-SCH_INST_START;   
2478
2479    if(!schPhrInd)
2480    {
2481       DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): PHR is empty");
2482       ret = RFAILED;
2483    }
2484    else
2485    {
2486       GET_CELL_IDX(schPhrInd->cellId, cellIdx);
2487       cell = schCb[inst].cells[cellIdx];
2488       if(cell == NULLP)
2489       { 
2490          DU_LOG("\nERROR  -->  SCH : schProcPhrInd(): cell Id[%d] is not found", schPhrInd->cellId);
2491          ret = RFAILED;
2492       }
2493       else
2494       {
2495          if(cell->cellId == schPhrInd->cellId)
2496          {
2497             GET_UE_ID(schPhrInd->crnti, ueId);
2498             ueCb = &cell->ueCb[ueId-1];
2499             if(ueCb->crnti != schPhrInd->crnti)
2500             {
2501                DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): UeCb for received crnti[%d] not found",schPhrInd->crnti);
2502                ret = RFAILED;
2503             }
2504             else
2505             {
2506                /*TODO: complete the processing of PHR Ind*/ 
2507             }
2508          }
2509          else
2510          {
2511             DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): Mismatch between Received cell Id[%d] from MAC and CellID[%d] in SCH CB ",\
2512                     schPhrInd->cellId, cell->cellId);
2513             ret = RFAILED;
2514          }
2515       }
2516    }
2517    return ret;
2518 }
2519
2520 /*******************************************************************
2521  *
2522  * @brief Fill and send statistics response to MAC
2523  *
2524  * @details
2525  *
2526  *    Function :  SchSendStatsRspToMac
2527  *
2528  *    Functionality: Fill and send statistics response to MAC
2529  *
2530  * @params[in]  Inst inst, SchMacRsp result
2531  * @return ROK     - success
2532  *         RFAILED - failure
2533  *
2534  * ****************************************************************/
2535 uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
2536 {
2537    Pst rspPst;
2538    uint8_t ret = ROK;
2539    SchStatsRsp  *schStatsRsp;
2540
2541    DU_LOG("\nINFO   --> SCH : Filling statistics response");
2542    SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
2543    if(schStatsRsp == NULLP)
2544    {
2545       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
2546       return RFAILED;
2547    }
2548  
2549    memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
2550    memset(statsRsp, 0, sizeof(SchStatsRsp));
2551
2552    /* Filling response post */
2553    memset(&rspPst, 0, sizeof(Pst));
2554    FILL_PST_SCH_TO_MAC(rspPst, inst);
2555    rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
2556
2557    ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
2558    if(ret == RFAILED)
2559    {
2560       DU_LOG("\nERROR  -->  SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
2561       return ret;
2562    }
2563    return ret;
2564 }
2565
2566 /*******************************************************************
2567  *
2568  * @brief Rejects all statistics group requested by MAC
2569  *
2570  * @details
2571  *
2572  *    Function : SchRejectAllStats
2573  *
2574  *    Functionality: Add all statistics group received in statistics
2575  *       request from MAC, to Reject-Stats-Group-List in statistics
2576  *       response to MAC
2577  *
2578  * @params[in]  Statistics request from MAC
2579  *              Cause of rejection
2580  * @return ROK     - success
2581  *         RFAILED - failure
2582  *
2583  * ****************************************************************/
2584 uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
2585 {
2586    uint8_t grpIdx = 0;
2587    SchStatsRsp schStatsRsp;
2588
2589    memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2590
2591    /* Copying all stats group from stats request to stats response */
2592    schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
2593    for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
2594    {
2595       schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
2596       schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
2597    }
2598    schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
2599
2600    return SchSendStatsRspToMac(&schStatsRsp);
2601 }
2602
2603 /*******************************************************************
2604  *
2605  * @brief Add active KPI pointers to KPI-Active-List
2606  *
2607  * @details
2608  *
2609  *    Function : schAddToKpiActiveList
2610  *
2611  *    Functionality: For each active statistics group for which timer
2612  *       is running, add its KPI pointer to KPI-Active-List.
2613  *       Use case :
2614  *       When it is needed to update a KPI parameters, we need not
2615  *       traverse all statistics group and all KPIs within a group
2616  *       to get the specific KPI pointer to be updated.
2617  *       Instead, we can traverse through KPI-Active-List and update
2618  *       all entries in this list.
2619  *
2620  * @params[in]  Pointer to the prb usage info link list
2621  *              Pointer to the stats ccnfig which we need to add
2622  * @return ROK     - success
2623  *         RFAILED - failure
2624  *
2625  * ****************************************************************/
2626 uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo)
2627 {
2628    CmLList  *node = NULLP;
2629
2630    SCH_ALLOC(node, sizeof(CmLList));
2631    if(node)
2632    {
2633       node->node = kpiStatsInfo; 
2634       cmLListAdd2Tail(kpiList, node);
2635       return ROK;
2636    }
2637    DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2638    return RFAILED;
2639 }
2640
2641  /*******************************************************************
2642  *
2643  * @brief add the stats group information in statistics's statsGrpList
2644  *
2645  * @details
2646  *
2647  *    Function : schAddToStatsGrpList
2648  *
2649  *    Functionality: add the stats group information in statsGrpList
2650  *    [Step 1] - Allocating the memory for the stats group in which 
2651  *          we need to fill into the list as a node.
2652  *    [Step 2] - If allocation is successful then start traversing 
2653  *          each measurment cfg index of received group info.
2654  *       [Step 2.1] Validate all measurements. If validation succeeds, go
2655  *       to [step 2.2]. Otherwise, reject the stats group and go to step 3.
2656  *       [Step 2.2] Add each KPI/measurementCfg into activeKpiList one by one.
2657  *       If it fails for any KPI, reject the whole statsGrp and go to step 3..
2658  *       [Step 2.3] Fill other group related information
2659  *       [Step 2.4] Initialise and start timer
2660  *       [Step 2.5] Once all validation and configuration is successful, add
2661  *       statsGrp node into statistic's StatsGrpList.
2662  *          [Step 2.5.1] If node successfully added to the list, then 
2663  *             fill the group related info in stats rsp's accepted list.
2664  *          [Step 2.5.2] Else goto step 3
2665  *    [Step 3] - If failed fill the group related info in stats rsp's 
2666  *          rejected list.
2667  *
2668  * @params[in]  
2669  *          Inst
2670  *          Pointer to the stats rsp
2671  *          Subscription Id
2672  *          Stats Grp Info which needs to be store in the list
2673  * @return ROK     - success
2674  *         RFAILED - failure
2675  *
2676  * ****************************************************************/
2677
2678 uint8_t schAddToStatsGrpList(Inst inst, struct schStatsRsp *statsRsp, uint64_t subscriptionId, SchStatsGrpInfo *grpInfo)
2679 {
2680    uint8_t ret =ROK;
2681    uint8_t grpIdx=0;
2682    uint8_t reqMeasIdx=0;
2683    CauseOfResult cause;
2684    bool measTypeInvalid=false;
2685    CmLList *statsGrpNode=NULLP; 
2686    SchStatsGrp *grpInfoDb = NULLP;
2687    
2688    /* Step 1 */
2689    SCH_ALLOC(grpInfoDb, sizeof(SchStatsGrp));
2690    if(grpInfoDb == NULLP)
2691    {
2692       DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2693       cause = RESOURCE_UNAVAILABLE;
2694       ret = RFAILED;
2695    }
2696    else
2697    {
2698       /* Step 2 */
2699       for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
2700       {
2701          /* Step 2.1 */
2702          switch(grpInfo->statsList[reqMeasIdx])
2703          {
2704             case SCH_DL_TOTAL_PRB_USAGE:
2705                {
2706                   SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
2707                   if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
2708                   {
2709                      DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2710                      measTypeInvalid = true;
2711                      cause = RESOURCE_UNAVAILABLE;
2712                      break;
2713                   }
2714                   break;
2715                }
2716
2717             case SCH_UL_TOTAL_PRB_USAGE:
2718                {
2719                   SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
2720                   if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
2721                   {
2722                      DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2723                      measTypeInvalid = true;
2724                      cause = RESOURCE_UNAVAILABLE;
2725                      break;
2726                   }
2727                   break;
2728                }
2729
2730             default:
2731                {
2732                   DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Invalid measurement type [%d]", \
2733                         grpInfo->statsList[reqMeasIdx]);
2734                   measTypeInvalid = true;
2735                   cause = PARAM_INVALID;
2736                   break;
2737                }
2738          }
2739
2740          if(measTypeInvalid)
2741          {
2742             ret =RFAILED;
2743             break;
2744          }
2745       }
2746
2747       while(measTypeInvalid==false)
2748       {
2749          if(grpInfoDb->kpiStats.dlTotalPrbUsage)
2750          {
2751             /* Step 2.2 */
2752             if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR)grpInfoDb->kpiStats.dlTotalPrbUsage)!=ROK)
2753             {
2754                DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2755                cause = RESOURCE_UNAVAILABLE;
2756                ret =RFAILED;
2757                break;
2758             }
2759          }
2760
2761          if(grpInfoDb->kpiStats.ulTotalPrbUsage)
2762          {
2763             /* Step 2.2 */
2764             if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK)
2765             {
2766                DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2767                cause = RESOURCE_UNAVAILABLE;
2768                ret =RFAILED;
2769                break;
2770             }
2771          }
2772
2773          /* Step 2.3 */
2774          grpInfoDb->schInst = inst;
2775          grpInfoDb->groupId = grpInfo->groupId;
2776          grpInfoDb->periodicity = grpInfo->periodicity;
2777          grpInfoDb->subscriptionId = subscriptionId;
2778
2779          /* Step 2.4 */
2780          cmInitTimers(&(grpInfoDb->periodTimer), 1);
2781          schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
2782
2783          /* Step 2.5 */
2784          SCH_ALLOC(statsGrpNode, sizeof(CmLList));
2785          if(statsGrpNode)
2786          {
2787             /* Step 2.5.1 */
2788             statsGrpNode->node = (PTR) grpInfoDb;
2789             cmLListAdd2Tail(&schCb[inst].statistics.statsGrpList, statsGrpNode);
2790             statsRsp->statsGrpAcceptedList[statsRsp->numGrpAccepted] = grpInfo->groupId;
2791             statsRsp->numGrpAccepted++;
2792             grpIdx++;
2793             ret =  ROK;
2794             break;
2795          }
2796          else
2797          {
2798             /* Step 2.5.2 */
2799             DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
2800             cause = RESOURCE_UNAVAILABLE;
2801             ret  = RFAILED;
2802             break;
2803          }
2804       }
2805    }
2806
2807    if(ret != ROK)
2808    {
2809       /* Step 3 */
2810       if(grpInfoDb)
2811       {
2812          deleteStatsGrpInfo(inst, grpInfoDb);      
2813          SCH_FREE(grpInfoDb, sizeof(SchStatsGrp));
2814       }
2815       statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].groupId = grpInfo->groupId;
2816       statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].cause = cause;
2817       statsRsp->numGrpRejected++;
2818       return RFAILED;
2819    }
2820    return ROK;
2821 }
2822
2823 /*******************************************************************
2824  *
2825  * @brief Processes Statistics Request from MAC
2826  *
2827  * @details
2828  *
2829  *    Function : SchProcStatsReq
2830  *
2831  *    Functionality:
2832  *
2833  *     This function process the statistics request from MAC:
2834  *     [Step 1] Basic validation. If fails, all stats group in stats request are
2835  *     rejected.
2836  *     [Step 2] If basic validations passed, traverse all stats group and
2837  *     validate each measurement types in each group.
2838  *     [Step 3] If any measurement type validation fails in a group, that group
2839  *     is not configured and it is added to stats-group-rejected-list in
2840  *     sch-stats-response message.
2841  *     [Step 4] If a group passes all validation, it is added to SCH database.
2842  *     And the group is added to stats-group-accepted-list in sch-stats-response message.
2843  *     [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
2844  *     and stats-group-accepted-list.
2845  *
2846  * @params[in] Post structure
2847  *             Statistics Request from MAC 
2848  * @return ROK     - success
2849  *         RFAILED - failure
2850  *
2851  * ****************************************************************/
2852 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
2853 {
2854    bool allocFailed = false;
2855    uint8_t grpIdx = 0, reqGrpIdx = 0;
2856    SchStatsGrpInfo *grpInfo = NULLP;
2857    SchStatsRsp schStatsRsp;
2858    Inst inst = pst->dstInst - SCH_INST_START;
2859
2860    DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
2861
2862    if(statsReq == NULLP)
2863    {
2864       DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Received Null pointer");
2865       return RFAILED;
2866    }
2867
2868    /*Step -1*/
2869    if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP)
2870    {
2871       DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Maximum number of statistics configured. \
2872             Cannot process new request.");
2873       SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
2874       SCH_FREE(statsReq, sizeof(SchStatsReq));
2875       return RFAILED;
2876    }
2877
2878    memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2879
2880    /*Step -2*/
2881    for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
2882    {
2883       grpInfo = &statsReq->statsGrpList[reqGrpIdx];
2884       /*Step -3 */
2885       if(allocFailed  == true)
2886       {
2887          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
2888          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
2889          schStatsRsp.numGrpRejected++;
2890       }
2891       else
2892       {
2893          /*Step -4 */
2894          if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
2895          {
2896             DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Failed to fill the stats group list");
2897             if((schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].groupId == grpInfo->groupId &&\
2898                      (schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)))
2899             { 
2900                allocFailed = true;
2901             }
2902          }
2903       }
2904    }
2905
2906    schStatsRsp.subscriptionId = statsReq->subscriptionId;
2907    SCH_FREE(statsReq, sizeof(SchStatsReq));
2908    
2909    /*Step -5 */
2910    SchSendStatsRspToMac(&schStatsRsp);
2911
2912    return ROK;
2913 }
2914
2915 /*******************************************************************
2916  *
2917  * @brief Fill and send statistics indication to MAC
2918  *
2919  * @details
2920  *
2921  *    Function :  SchSendStatsIndToMac
2922  *
2923  *    Functionality: Fill and send statistics indication to MAC
2924  *
2925  * @params[in]  SCH Instance
2926  *              Measurement Type
2927  *              Measurement Value
2928  *              Size of value parameter
2929  * @return ROK     - success
2930  *         RFAILED - failure
2931  *
2932  * ****************************************************************/
2933 uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd  *statsInd)
2934 {
2935    Pst pst;
2936    uint8_t ret = ROK;
2937
2938 #ifdef DEBUG_PRINT
2939    DU_LOG("\nDEBUG  --> SCH : Filling statistics indication");
2940 #endif
2941
2942    /* Filling post structure */
2943    memset(&pst, 0, sizeof(Pst));
2944    FILL_PST_SCH_TO_MAC(pst, inst);
2945    pst.event = EVENT_STATISTICS_IND_TO_MAC;
2946
2947    ret = MacMessageRouter(&pst, (void *)statsInd);
2948    if(ret == RFAILED)
2949    {
2950       DU_LOG("\nERROR  -->  SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
2951    }
2952    return ret;
2953 }
2954
2955 /**
2956  * @brief Handler to process Timer expiry of DL Total PRB Usage calculation 
2957  *
2958  * @param[in] cb        Control block depending on the type of the timer event.
2959  * @param[in] tmrEvnt   Timer event to be started
2960  *
2961  * @return  Bool indicating whether the timer is running or not
2962  *      -# ROK
2963  *      -# RFAILED
2964 */
2965 double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
2966 {
2967    double percentageOfTotalPrbUsed = 0;
2968
2969    if(dlTotalPrbUsage->totalPrbAvailForTx)
2970       percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
2971    
2972    memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2973
2974    return percentageOfTotalPrbUsed;
2975 }
2976
2977 /**
2978  * @brief Handler to check if the timer is running
2979  *
2980  * @param[in] cb        Control block depending on the type of the timer event.
2981  * @param[in] tmrEvnt   Timer event to be started
2982  *
2983  * @return  Bool indicating whether the timer is running or not
2984  *      -# ROK
2985  *      -# RFAILED
2986 */
2987 uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
2988 {
2989    double percentageOfTotalPrbUsed = 0;
2990
2991    if(ulTotalPrbUsage->totalPrbAvailForTx)
2992       percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
2993
2994    memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2995
2996    return percentageOfTotalPrbUsed;
2997 }
2998
2999 /**
3000  * @brief Calculates statistics in a group and sends
3001  *          statistics indication for this group
3002  *
3003  * @param[in] Statistics group info
3004  *
3005  * @return
3006  *      -# ROK
3007  *      -# RFAILED
3008 */
3009 uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
3010 {
3011    uint8_t measStatsIdx = 0;
3012    SchStatsInd  statsInd;
3013
3014    memset(&statsInd, 0, sizeof(SchStatsInd));
3015    statsInd.subscriptionId = grpInfo->subscriptionId;
3016    statsInd.groupId = grpInfo->groupId;
3017
3018    if(grpInfo->kpiStats.dlTotalPrbUsage)
3019    {
3020       statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;  
3021       statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);   
3022       measStatsIdx++;
3023    }
3024    
3025    if(grpInfo->kpiStats.ulTotalPrbUsage)
3026    {
3027       statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;  
3028       statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);   
3029       measStatsIdx++;
3030    }
3031    
3032    statsInd.numStats = measStatsIdx;
3033
3034    return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
3035 }
3036
3037 /*******************************************************************
3038  *
3039  * @brief Delete node from active kpi list
3040  *
3041  * @details
3042  *
3043  *    Function :deleteNodeFrmKpiList 
3044  *
3045  *    Functionality:
3046  *    Delete statistics group
3047  *
3048  * @params[in]
3049  *           Kpi list from which a node needs to be deleted
3050  *           Nodes info which a node needs to be deleted
3051  * @return void
3052  * ****************************************************************/
3053
3054 void deleteNodeFrmKpiList(CmLListCp *kpiList, PTR kpiNodeInfoToDel)
3055 {
3056    CmLList *kpiNode=NULLP;
3057
3058    CM_LLIST_FIRST_NODE(kpiList, kpiNode);
3059    while(kpiNode)
3060    {
3061       if(kpiNode->node == kpiNodeInfoToDel)
3062       {
3063          cmLListDelFrm(kpiList, kpiNode);
3064          SCH_FREE(kpiNode, sizeof(CmLList));
3065          break;
3066       }
3067       kpiNode = kpiNode->next;
3068    }
3069
3070 }
3071
3072 /*******************************************************************
3073  *
3074  * @brief Delete statistics group info
3075  *
3076  * @details
3077  *
3078  *    Function : deleteStatsGrpInfo
3079  *
3080  *    Functionality:
3081  *    Delete statistics group info
3082  *
3083  * @params[in]
3084  *           Inst
3085  *           Stats Grp info
3086  * @return void
3087  *
3088  * ****************************************************************/
3089 void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo)
3090 {
3091    if(statsGrpInfo)
3092    {
3093       if(statsGrpInfo->kpiStats.dlTotalPrbUsage)
3094       {
3095          deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR) statsGrpInfo->kpiStats.dlTotalPrbUsage);
3096          SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
3097       }
3098
3099       if(statsGrpInfo->kpiStats.ulTotalPrbUsage)
3100       {
3101          deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR) statsGrpInfo->kpiStats.ulTotalPrbUsage);
3102          SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
3103       }
3104
3105       if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3106       {
3107          schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3108       }
3109
3110       memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3111    }
3112 }
3113
3114 /*******************************************************************
3115  *
3116  * @brief Delete statistics group Node
3117  *
3118  * @details
3119  *
3120  *    Function : deleteStatsGrpNode
3121  *
3122  *    Functionality:
3123  *    Delete statistics group node
3124  *
3125  * @params[in]
3126  *           Inst
3127  *           Stats Grp Node
3128  * @return void
3129  *
3130  * ****************************************************************/
3131 void deleteStatsGrpNode(Inst inst, CmLList *grpNode)
3132 {
3133    SchStatsGrp *statsGrpInfo=NULLP;
3134
3135    if(grpNode)
3136    {
3137       statsGrpInfo = (SchStatsGrp*)grpNode->node;
3138       deleteStatsGrpInfo(inst, statsGrpInfo);      
3139       memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3140       SCH_FREE(grpNode->node, sizeof(SchStatsGrp));
3141       SCH_FREE(grpNode, sizeof(CmLList));
3142    }
3143 }
3144
3145 /******************************************************************
3146  *
3147  * @brief Deletion of node from statistics group list
3148  *
3149  * @details
3150  *
3151  *    Function : deleteFromStatsGrpList
3152  *
3153  *    Functionality: Deletion of node from statistics group list
3154  *    [Step 1]: Traverse each and every node of stats group list
3155  *    stored in the database
3156  *    [Step 2]: Check if the node's subscription id is same 
3157  *    as the subscription id received. If same then go to step 3
3158  *    else move to the next node of the list.
3159  *    [Step 3]: If deleteAllGrp == true, then delete the node and 
3160  *    move to the next node of the list.
3161  *    [Step 4]: If deleteAllGrp != true, then check if the node's group
3162  *    id is same as group id received then delete the node and mark the 
3163  *    status found true else move to the next node of the list.
3164  *    [Step 5]: Once the traversing complete,  
3165  *    if deleteAllGrp is true, then return successful rsp;
3166  *    else if status found is true, then return  successful rsp;
3167  *    else return failure.
3168  * @params[in] 
3169  *           Inst
3170  *           Stats Grp List 
3171  *           Subscription Id
3172  *           Group Id
3173  *           boolen of deleteAllGrp
3174  * @return void
3175  *
3176  * ****************************************************************/
3177 uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t  subscriptionId, uint8_t  groupId, bool deleteAllGrp)
3178 {
3179    bool statsFound=false;
3180    SchStatsGrp *statsGrpInfo=NULLP;
3181    CmLList *grpNode=NULLP;
3182
3183    /* [Step 1] */
3184    CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3185    while(grpNode)
3186    {
3187       statsGrpInfo = (SchStatsGrp*)grpNode->node;
3188
3189       /* [Step 2] */
3190       if(statsGrpInfo->subscriptionId== subscriptionId) 
3191       {
3192          if(deleteAllGrp == true)
3193          {
3194             /* [Step 3] */
3195             cmLListDelFrm(statsGrpList, grpNode);
3196             deleteStatsGrpNode(inst, grpNode);
3197          }
3198          else
3199          {
3200             /* [Step 4] */
3201             if(statsGrpInfo->groupId== groupId) 
3202             {
3203                cmLListDelFrm(statsGrpList, grpNode);
3204                deleteStatsGrpNode(inst, grpNode);
3205                statsFound = true;
3206             }
3207          }
3208       }
3209       CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3210    }
3211
3212    /* [Step 5] */
3213    if(deleteAllGrp == true)
3214    {
3215       return ROK;
3216    }
3217    else
3218    {
3219       if(statsFound == true)
3220          return ROK;
3221    }
3222    return RFAILED;
3223 }
3224
3225 /*******************************************************************
3226  *
3227  * @brief Delete statistics information 
3228  *
3229  * @details
3230  *
3231  *    Function : deleteStatsInfo 
3232  *
3233  *    Functionality:
3234  *   Delete statistics information base on numStatsGroup 
3235  *   Info- If numStatsGroup = 0' indicates the Deletion procedure triggered by
3236  *   'SUBS_DELETION_REQ' wherein all the groups of this particular
3237  *   Subscription has to be removed 
3238  *   else when numStatsGroup != 0 then this is
3239  *   for SUBS_MOD_REQ's actionToBeDeleted wherein particular action(s) has
3240  *   to be removed thus need to pass groupId belonging to that subscription
3241  *   which has to be deleted.'
3242  *
3243  *   [Step-1] If numStatsGroup = 0, Deletion of all stats group belonging to
3244  *   received subscription Id.
3245  *   [Step-2] Else if numStatsGroup > 0, Deletion of individual stats group 
3246  *   from list whose information are present in stats delete request.
3247  *   [Step-3] Fill the result of the stats deletion in the SCH stats delete
3248  *   response
3249  * @params[in] 
3250  *             Instance
3251  *             Subscription delete req
3252  *             Subscription delete rsp
3253  * @return ROK     - success
3254  *         RFAILED - failure
3255  *
3256  * ****************************************************************/
3257 uint8_t deleteStatsInfo(Inst inst, SchStatsDeleteReq *statsDeleteReq, SchStatsDeleteRsp  *schStatsDeleteRsp)
3258 {
3259    uint8_t statsGrpIdx=0;
3260    CmLListCp  *statsGrpList =NULLP;
3261
3262    statsGrpList = &schCb[inst].statistics.statsGrpList;
3263    
3264    if(!statsDeleteReq->numStatsGroupToBeDeleted)
3265    {
3266       /* [Step-1] */
3267       if(deleteFromStatsGrpList(inst,statsGrpList, statsDeleteReq->subscriptionId, 0, true) == ROK)
3268       {
3269          /* [Step 3]*/
3270          schStatsDeleteRsp->subsDelRsp = RSP_OK;  
3271          schStatsDeleteRsp->subsDelCause = SUCCESSFUL;
3272       }
3273       else
3274       {
3275          /* [Step-3]*/
3276          schStatsDeleteRsp->subsDelRsp = RSP_NOK;  
3277          schStatsDeleteRsp->subsDelCause = STATS_ID_NOT_FOUND; 
3278       }
3279    }
3280    else
3281    {
3282       for(statsGrpIdx=0; statsGrpIdx<statsDeleteReq->numStatsGroupToBeDeleted; statsGrpIdx++)
3283       {
3284          /* [Step-2] */
3285          if(deleteFromStatsGrpList(inst, statsGrpList, statsDeleteReq->subscriptionId,\
3286                   statsDeleteReq->statsGrpIdToBeDelList[statsGrpIdx], false) == ROK)
3287          {
3288             /* [Step-3]*/
3289             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_OK;  
3290             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = SUCCESSFUL; 
3291          }
3292          else
3293          {
3294             /* [Step-3]*/
3295             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_NOK;  
3296             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = STATS_ID_NOT_FOUND; 
3297          }
3298       }
3299       schStatsDeleteRsp->numStatsGroupDeleted = statsDeleteReq->numStatsGroupToBeDeleted;
3300    }
3301    return ROK;
3302 }
3303
3304 /*******************************************************************
3305  *
3306  * @brief Processes Statistics Delete Request from MAC
3307  *
3308  * @details
3309  *
3310  *    Function : SchProcStatsDeleteReq
3311  *
3312  *    Functionality:
3313  *     This function process the statistics delete request from MAC:
3314  *
3315  * @params[in] Post structure
3316  *             Statistics Delete Request from MAC
3317  * @return ROK     - success
3318  *         RFAILED - failure
3319  *
3320  * ****************************************************************/
3321 uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
3322 {
3323    Pst rspPst;
3324    uint8_t ret =ROK;
3325    SchStatsDeleteRsp  *schStatsDeleteRsp;
3326    Inst    inst = pst->dstInst - SCH_INST_START;
3327
3328    DU_LOG("\nINFO   -->  SCH : Received Statistics Delete Request from MAC");
3329
3330    if(statsDeleteReq == NULLP)
3331    {
3332       DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Received Null pointer");
3333       return RFAILED;
3334    }
3335    
3336    /* Process Stats delete request and fill stats delete response simultaneously */
3337    SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
3338    if(schStatsDeleteRsp == NULLP)
3339    {
3340       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchProcStatsDeleteReq()");
3341       return RFAILED;
3342    }
3343    schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
3344    deleteStatsInfo(inst, statsDeleteReq, schStatsDeleteRsp);
3345    
3346    memset(&rspPst, 0, sizeof(Pst));
3347    FILL_PST_SCH_TO_MAC(rspPst, inst);
3348    rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC;
3349
3350    ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp);
3351    if(ret == RFAILED)
3352    {
3353       DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Failed to send Statistics Response");
3354    }
3355    SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
3356
3357    return ret;
3358 } /* End of SchProcStatsDeleteReq */
3359
3360 /*******************************************************************
3361  *
3362  * @brief Fill and send statistics modification response to MAC
3363  *
3364  * @details
3365  *
3366  *    Function :  SchSendStatsRspToMac
3367  *
3368  *    Functionality: Fill and send statistics
3369  * modification response to MAC
3370  *
3371  * @params[in]  Inst inst, SchMacRsp result
3372  * @return ROK     - success
3373  *         RFAILED - failure
3374  *
3375  * ****************************************************************/
3376 uint8_t SchSendStatsModificationRspToMac(SchStatsModificationRsp *tmpSchStatsModRsp)
3377 {
3378    Pst rspPst;
3379    uint8_t ret = ROK;
3380    SchStatsModificationRsp  *schStatsModificationRsp=NULLP;
3381
3382    DU_LOG("\nINFO   --> SCH : Filling statistics modification response");
3383    SCH_ALLOC(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
3384    if(schStatsModificationRsp == NULLP)
3385    {
3386       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsModificationRspToMac()");
3387       return RFAILED;
3388    }
3389
3390    memcpy(schStatsModificationRsp, tmpSchStatsModRsp, sizeof(SchStatsModificationRsp));
3391    memset(tmpSchStatsModRsp, 0, sizeof(SchStatsModificationRsp));
3392
3393    /* Filling response post */
3394    memset(&rspPst, 0, sizeof(Pst));
3395    FILL_PST_SCH_TO_MAC(rspPst, inst);
3396    rspPst.event = EVENT_STATISTICS_MODIFY_RSP_TO_MAC;
3397
3398    ret = MacMessageRouter(&rspPst, (void *)schStatsModificationRsp);
3399    if(ret == RFAILED)
3400    {
3401       DU_LOG("\nERROR  -->  SCH : SchSendStatsModificationRspToMac(): Failed to send Statistics Modification Response");
3402       return ret;
3403    }
3404    return ret;
3405 }
3406
3407 /*******************************************************************
3408  *
3409  * @brief Rejects all statistics modification group requested by MAC
3410  *
3411  * @details
3412  *
3413  *    Function : SchRejectAllStatsModification
3414  *
3415  *    Functionality: Add all statistics modification group received in statistics
3416  *       request from MAC, to Reject-StatsModification-Group-List in statistics
3417  *       response to MAC
3418  *
3419  * @params[in]  Statistics request from MAC
3420  *              Cause of rejection
3421  * @return ROK     - success
3422  *         RFAILED - failure
3423  *
3424  * ****************************************************************/
3425 uint8_t SchRejectAllStatsModification(SchStatsModificationReq *statsModificationReq, CauseOfResult cause)
3426 {
3427    uint8_t grpIdx = 0;
3428    SchStatsModificationRsp statsModificationRsp;
3429
3430    memset(&statsModificationRsp, 0, sizeof(SchStatsModificationRsp));
3431
3432    /* fill the subscriptionId and the rejected list in stats modification rsp */
3433    statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3434    for(grpIdx = 0; grpIdx < statsModificationReq->numStatsGroup; grpIdx++)
3435    {
3436       statsModificationRsp.statsGrpRejectedList[grpIdx].groupId = statsModificationReq->statsGrpList[grpIdx].groupId;
3437       statsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause;
3438    }
3439    statsModificationRsp.numGrpRejected = statsModificationReq->numStatsGroup;
3440
3441    return SchSendStatsModificationRspToMac(&statsModificationRsp);
3442 }
3443
3444 /****************************************************************************************
3445 *
3446 * @brief Processes Statistics modification Request from MAC
3447 *
3448 * @details
3449 *
3450 *    Function :SchProcStatsModificationReq 
3451 *
3452 *    Functionality:
3453 *     This function process the statistics modification request from MAC:
3454 *     [Step -1] Check the stored stats group list empty.
3455 *        [Step - 1.1] If empty Send the rejected group list to MAC as a stats 
3456 *        modification response.
3457 *        [Step - 1.2] Else go to step 2.
3458 *     [Step -2] Traverse all stats group and validate each measurement types in
3459 *     each group.
3460 *     [Step -3] Check for any failure and if failed fill the remaining group's
3461 *     info in rejected list.
3462 *     [Step -4] Else Check if the received subscriptionId and groupId match the 
3463 *     values with the database node. 
3464 *        [Step -4.1] If  matches then follow the below mentioned steps.
3465 *           [Step -4.1.1] Stop the timer.
3466 *           [Step -4.1.2] Reconfigure stats group by adding a new entry for this
3467 *           statsGroup with updated configuration in database.
3468 *           [Step -4.1.3] if configured successfully, store stats info into
3469 *           stats mod rsp's accepted list, restart timer and go to step 4.1.4 
3470 *           [Step -4.1.4] Delete the old entry of this stats group..
3471 *        [Step -4.2] Else fill the group related info in stats modification rsp's 
3472 *           rejected list.
3473 *     [Step -5] Send the stats modification rsp to MAC
3474 * @params[in] Post structure
3475 *             Statistics modification Request from MAC
3476 * @return ROK     - success
3477 *         RFAILED - failure
3478 *
3479 * *******************************************************************************************/
3480 uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq)
3481 {
3482    Inst inst;
3483    uint8_t reqGrpIdx=0;
3484    uint64_t subscriptionId =0;
3485    bool allocFailed = false;
3486    bool statsGrpFound= false;
3487    CmLList *grpNode = NULLP;
3488    SchStatsGrp *statsGrpInfo=NULLP;
3489    SchStatsGrpInfo statsGrpToModify;
3490    SchStatsModificationRsp statsModificationRsp;
3491
3492    inst=pst->dstInst - SCH_INST_START;
3493
3494    DU_LOG("\nINFO   -->  SCH : Received Statistics modification request from MAC");
3495
3496    if(statsModificationReq == NULLP)
3497    {
3498       DU_LOG("\nERROR  -->  SCH : SchProcStatsModificationReq(): Received Null pointer");
3499       return RFAILED;
3500    }
3501    memset(&statsModificationRsp, 0, sizeof(SchStatsRsp));
3502
3503    /* [Step -1] */
3504    if(schCb[inst].statistics.statsGrpList.count)
3505    {
3506       /* [Step -1.2] */
3507       subscriptionId = statsModificationReq->subscriptionId;
3508
3509       /* [Step - 2] */
3510       for(reqGrpIdx=0; reqGrpIdx<statsModificationReq->numStatsGroup; reqGrpIdx++)
3511       {
3512          /* [Step - 3] */
3513          statsGrpToModify = statsModificationReq->statsGrpList[reqGrpIdx];
3514          if(allocFailed  != true)
3515          {
3516             CM_LLIST_FIRST_NODE(&schCb[inst].statistics.statsGrpList, grpNode);
3517             while(grpNode)
3518             {
3519                /* [Step - 4] */
3520                statsGrpInfo = (SchStatsGrp*)grpNode->node;
3521                if((statsGrpInfo->subscriptionId== subscriptionId) && (statsGrpInfo->groupId== statsGrpToModify.groupId))
3522                {
3523                   statsGrpFound= true;
3524                   break; 
3525                }
3526                grpNode = grpNode->next;
3527             }
3528
3529             /* [Step - 4.1] */
3530             if(statsGrpFound== true)
3531             {
3532                /* [Step - 4.1.1] */
3533                if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3534                {
3535                   schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3536                }
3537
3538                /* [Step - 4.1.2] */
3539                if(schAddToStatsGrpList(inst, &statsModificationRsp, subscriptionId, &statsGrpToModify) != ROK)
3540                {
3541                   DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Failed to fill the stats group list");
3542                   if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].groupId == statsGrpToModify.groupId)
3543                   {
3544                      /* [Step - 4.1.3] */
3545                      schStartTmr(&schCb[inst], (PTR)(statsGrpInfo), EVENT_STATISTICS_TMR, statsGrpInfo->periodicity);
3546                      if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)
3547                      {
3548                         allocFailed = true;
3549                         break;
3550                      }
3551                   }
3552                }
3553                else
3554                {
3555                   /* [Step - 4.1.4] */
3556                   deleteStatsGrpNode(inst, grpNode);
3557                }
3558             }
3559             else
3560             {
3561                /* [Step - 4.2] */
3562                statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3563                statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = STATS_ID_NOT_FOUND;
3564                statsModificationRsp.numGrpRejected++;
3565             }
3566          }
3567          else
3568          {
3569             statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3570             statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
3571             statsModificationRsp.numGrpRejected++;
3572          }
3573       }
3574
3575       statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3576       SchSendStatsModificationRspToMac(&statsModificationRsp);
3577    }
3578    else
3579    {
3580       /* [Step -1.1] */
3581       SchRejectAllStatsModification(statsModificationReq, STATS_ID_NOT_FOUND);
3582    }
3583    SCH_FREE(statsModificationReq, sizeof(SchStatsModificationReq));
3584    return ROK;
3585 }
3586 /**********************************************************************
3587   End of file
3588  **********************************************************************/