f09225b0f3bd1d9fbf24af5eb143aced509c30e2
[o-du/l2.git] / src / du_app / du_cell_mgr.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 /* This file contains message handling functionality for DU cell management */
20 #include "common_def.h"
21 #include "du_tmr.h"
22 #include "lrg.h"
23 #include "legtp.h"
24 #include "lrg.x"
25 #include "lkw.x"
26 #include "rgr.h"
27 #include "rgr.x"
28 #include "du_app_mac_inf.h"
29 #include "du_app_rlc_inf.h"
30 #include "du_e2ap_mgr.h"
31 #include "du_cfg.h"
32 #include "du_mgr.h"
33 #include "du_utils.h"
34 #include "du_cell_mgr.h"
35 #include "PCCH-Config.h"
36 #include "PagingUE-Identity.h"
37 #include "PagingRecord.h"
38 #include "PagingRecordList.h"
39 #include "PagingRrc.h"
40 #include "PCCH-MessageType.h"
41 #include "PCCH-Message.h"
42 #include "odu_common_codec.h"
43
44 #ifdef O1_ENABLE
45
46 #include "AlarmInterface.h"
47 #include "CmInterface.h"
48
49 #endif
50
51 GConfiguration gConfigInfo;
52 DuMacCellDeleteReq packMacCellDeleteReqOpts[] =
53 {
54    packDuMacCellDeleteReq,       /* Loose coupling */
55    MacProcCellDeleteReq,         /* TIght coupling */
56    packDuMacCellDeleteReq        /* Light weight-loose coupling */
57 };
58
59 DuMacDlPcchInd packMacDlPcchIndOpts[] =
60 {
61    packDuMacDlPcchInd,       /* Loose coupling */
62    MacProcDlPcchInd,         /* TIght coupling */
63    packDuMacDlPcchInd        /* Light weight-loose coupling */
64 };
65
66 DuMacDlBroadcastReq packMacDlBroadcastReqOpts[] =
67 {
68    packDuMacDlBroadcastReq,       /* Loose coupling */
69    MacProcDlBroadcastReq,         /* TIght coupling */
70    packDuMacDlBroadcastReq        /* Light weight-loose coupling */
71 };
72 /*******************************************************************
73  *
74  * @brief Processes cells to be activated
75  *
76  * @details
77  *
78  *    Function : duProcCellsToBeActivated
79  *
80  *    Functionality:
81  *      - Processes cells to be activated list received in F1SetupRsp
82  *
83  * @params[in] void
84  * @return ROK     - success
85  *         RFAILED - failure
86  *
87  * ****************************************************************/
88 uint8_t duProcCellsToBeActivated(uint8_t *plmnStr, uint16_t nci, uint16_t nRPci)
89 {
90    uint8_t ret = ROK;
91    DuCellCb *cellCb = NULLP;
92    uint8_t cfgIdx, tmpPlmn[4];
93
94    for(cfgIdx=0; cfgIdx<duCb.numCfgCells; cfgIdx++)
95    {
96       memset(tmpPlmn, 0, 4);
97       buildPlmnId(duCb.cfgCellLst[cfgIdx]->cellInfo.nrEcgi.plmn, tmpPlmn);
98       if(duCb.cfgCellLst[cfgIdx]->cellInfo.nrEcgi.cellId == nci &&
99             (strcmp((const char*)tmpPlmn, (const char*)plmnStr) == 0))
100       {
101          cellCb = duCb.cfgCellLst[cfgIdx];
102          break;
103       }
104       else
105       {
106          DU_LOG("\nERROR  -->  DU APP : No Cell found for NCI %d", nci);
107          return RFAILED;
108       }
109    }
110
111    cellCb->cellStatus = ACTIVATION_IN_PROGRESS; 
112    cellCb->cellInfo.nrPci = nRPci;
113
114    if((cmHashListInit(&(cellCb->pagingInfoMap), MAX_SFN, sizeof(DuPagInfoList),\
115                 FALSE, CM_HASH_KEYTYPE_CONID, DU_APP_MEM_REGION, DU_POOL)) != ROK)
116    {
117       DU_LOG("ERROR  --> DU APP: Failed to Initialize the Paging Hash Map");
118       return RFAILED;             
119    }
120    duCb.actvCellLst[cellCb->cellId -1] = cellCb;
121    duCb.numActvCells++;
122
123    if(duBuildAndSendMacCellCfg(cellCb->cellId) != ROK)
124    {
125       DU_LOG("\nERROR  -->  DU APP : macCellCfg build and send failed");
126       /* Delete cell from actvCellList */
127       duCb.actvCellLst[cellCb->cellId -1] = NULLP;
128       --(duCb.numActvCells);
129       ret = RFAILED;
130    }
131    return ret;
132 }
133
134 /*******************************************************************
135  *
136  * @brief Handles DU F1Setup Rsp received in F1AP
137  *
138  * @details
139  *
140  *    Function : duProcF1SetupRsp
141  *
142  *    Functionality:
143  *      - Handles DU F1Setup Rsp received in F1AP
144  *
145  * @params[in] Pointer to F1SetupRsp 
146  * @return void
147  *
148  ******************************************************************/
149 void duProcF1SetupRsp()
150 {
151    DU_LOG("\nINFO   -->  DU_APP : F1 Setup Response received");
152    duCb.f1Status = TRUE; //Set F1 status as true
153 }
154
155 /*******************************************************************
156 *
157 * @brief Returns cellCb based on cell ID
158 *
159 * @details
160 *
161 *    Function : duGetCellCb
162 *
163 *    Functionality: Returns DU APP CellCb based on cell ID
164 *
165 * @params[in] F1AP_PDU_t ASN decoded F1AP message
166 * @return ROK     - success
167 *         RFAILED - failure
168 *
169 * ****************************************************************/
170 uint8_t duGetCellCb(uint16_t cellId, DuCellCb **cellCb)
171 {
172    uint8_t cellIdx = 0;
173
174    for(cellIdx=0; cellIdx < MAX_NUM_CELL; cellIdx++)
175    {
176       if(duCb.actvCellLst[cellIdx] && (duCb.actvCellLst[cellIdx]->cellId == cellId))
177       {
178          *cellCb = duCb.actvCellLst[cellIdx];
179               break;
180       }
181    }
182
183    if(!*cellCb)
184    {
185       DU_LOG("\nERROR  -->  DU APP : Cell Id %d not found in DU APP", cellId);
186       return RFAILED;
187    }
188
189    return ROK;
190 }
191
192 /******************************************************************************
193 * @brief Check Paging Record for a Particular Paging Frame
194 *
195 * @details
196 *
197 *   Function : checkPagingRecord
198 *
199 *   Functionality:
200 *           Check Paging Record for a Particular Paging Frame
201
202 *  @params[in] DuCellCb *cellCb
203 *
204 *  @return ROK/RFAILURE (uint8_t return)
205
206
207 ******************************************************************************/
208 uint8_t checkPagingRecord(DuCellCb *cellCb)
209 {
210    uint16_t pf = 0;
211    DuPagInfoList *pagInfoLLFromPF = NULLP;
212    DuPagUeList *pagInfo = NULLP;
213
214    /*DUAPP may send PagingReq to MAC for future SFN so that Schedular can 
215     * schedule Paging on the exact occurence of the Slot.*/
216    pf = (cellCb->currSlotInfo.sfn + PAGING_SCHED_DELTA) % MAX_SFN;
217
218    pagInfoLLFromPF = findPagingInfoFromMap(pf, &(cellCb->pagingInfoMap));
219    if(pagInfoLLFromPF == NULLP)
220    {
221       /*No Page is present for pf thus exiting*/
222       return ROK;
223    }
224   
225    do
226    {
227       pagInfo = handlePageInfoLL(pf, NULLD, &(pagInfoLLFromPF->pagInfoList), TRAVERSE_ALL);
228       if(pagInfo != NULLP)
229       {
230          if(BuildAndSendDlPcchIndToMac(cellCb->cellId, pf, pagInfo->i_s, &(pagInfo->pagUeList)) != ROK)
231          {
232             DU_LOG("\nERROR  -->  DU APP: Issue in Building Page RRC PDU i_s:%d",pagInfo->i_s);
233             return RFAILED; 
234          }
235          handlePageInfoLL(pf, pagInfo->i_s, &(pagInfoLLFromPF->pagInfoList), DELETE);
236       }
237       if(pagInfoLLFromPF->pagInfoList.first == NULLP)
238       {
239          break;
240       }
241    }while(pagInfo != NULLP);
242    
243    cmHashListDelete(&(cellCb->pagingInfoMap), (PTR)pagInfoLLFromPF);
244    DU_FREE(pagInfoLLFromPF, sizeof(DuPagInfoList));
245    return ROK;
246 }
247
248 /******************************************************************
249  *
250  * @brief Send pcch indication to MAC
251  *
252  * @details
253  *
254  *    Function : sendDlPcchIndToMac
255  *
256  *    Functionality: Send pcch indication to MAC
257  *
258  * @Params[in] DlPcchInd *pcchInd
259  * @return ROK     - success
260  *         RFAILED - failure
261  *
262  * ****************************************************************/
263
264 uint8_t sendDlPcchIndToMac(DlPcchInd *pcchInd)
265 {
266    uint8_t ret = ROK;
267    Pst pst;
268
269    if(pcchInd)
270    {
271       /* Fill Pst */
272       FILL_PST_DUAPP_TO_MAC(pst, EVENT_MAC_DL_PCCH_IND);
273       
274       ret = (*packMacDlPcchIndOpts[pst.selector])(&pst, pcchInd);
275       if(ret == RFAILED)
276       {
277          DU_LOG("\nERROR  -->  DU APP : sendDlPcchIndToMac(): Failed to DL PCCH indication to MAC");
278       }
279    }
280    else
281    {
282       DU_LOG("\nERROR  -->  DU APP: sendDlPcchIndToMac(): Received pcchInd is NULLP");
283       ret = RFAILED;
284    }
285    return ret;
286 }
287
288
289 /*****************************************************************
290 * @brief Handles slot indication from MAC
291 *
292 * @details
293 *
294 *   Function : duHandleSlotInd
295 *
296 *   Functionality:
297 *       Handles  slot indication from MAC
298
299 *  @params[in] Post structure pointer
300 *              SlotTimingInfo *slotIndInfo
301 *  @return ROK     - success
302 *          RFAILED - failure
303
304
305 *****************************************************************/
306 uint8_t duHandleSlotInd(Pst *pst, SlotTimingInfo *slotIndInfo)
307 {
308    uint8_t cellIdx = 0, ret = ROK;
309    DuCellCb *duCellCb = NULLP;
310
311    if(slotIndInfo)
312    {
313       GET_CELL_IDX(slotIndInfo->cellId, cellIdx);
314       duCellCb = duCb.actvCellLst[cellIdx];
315
316       if(duCellCb)
317       {
318          duCellCb->currSlotInfo.sfn = slotIndInfo->sfn;
319          duCellCb->currSlotInfo.slot = slotIndInfo->slot;
320          checkPagingRecord(duCellCb);
321       }
322       else
323       {
324          DU_LOG("\nERROR  -->  DU APP : CellId[%d] doesnot exist", slotIndInfo->cellId);
325          ret = RFAILED;
326       }
327       DU_FREE_SHRABL_BUF(pst->region, pst->pool, slotIndInfo, sizeof(SlotTimingInfo));
328    }
329    else
330    {
331       DU_LOG("\nERROR  -->  DU APP : Recevied null pointer from MAC");
332       ret = RFAILED;
333    }
334    return(ret);
335 }
336 /*******************************************************************
337  *
338  * @brief Handles cell up indication from MAC
339  *
340  * @details
341  *
342  *    Function : duHandleCellUpInd
343  *
344  *    Functionality:
345  *      Handles cell up indication from MAC
346  *
347  * @params[in] Post structure pointer
348  *             cell Up info
349  * @return ROK     - success
350  *         RFAILED - failure
351  *
352  * ****************************************************************/
353 uint8_t duHandleCellUpInd(Pst *pst, OduCellId *cellId)
354 {
355    DuCellCb *cellCb = NULLP; 
356
357    if(cellId->cellId <=0 || cellId->cellId > MAX_NUM_CELL)
358    {
359       DU_LOG("\nERROR  -->  DU APP : Invalid Cell Id %d in duHandleCellUpInd()", cellId->cellId);
360       return RFAILED;
361    }
362
363    if(duGetCellCb(cellId->cellId, &cellCb) != ROK)
364       return RFAILED;
365
366    if((cellCb != NULL) && (cellCb->cellStatus == ACTIVATION_IN_PROGRESS))
367    {
368       DU_LOG("\nINFO   -->  DU APP : 5G-NR Cell %d is UP", cellId->cellId);
369       cellCb->cellStatus = ACTIVATED;
370       gConfigInfo.gCellStatus = CELL_UP;
371
372       if(duCfgParam.tempSliceCfg.numOfRrmPolicy)
373          BuildAndSendSliceConfigReq();
374 #ifdef O1_ENABLE
375       DU_LOG("\nINFO   -->  DU APP : Raise cell UP alarm for cell id=%d", cellId->cellId);
376       raiseCellAlrm(CELL_UP_ALARM_ID, cellId->cellId);
377       setCellOpState(cellId->cellId, ENABLED, ACTIVE);
378 #endif
379        duCfgParam.macCellCfg.cellCfg.opState = OP_ENABLED;
380        duCfgParam.macCellCfg.cellCfg.cellState = CELL_ACTIVE;
381    }
382
383    if((pst->selector == ODU_SELECTOR_LWLC) || (pst->selector == ODU_SELECTOR_TC))
384       DU_FREE_SHRABL_BUF(pst->region, pst->pool, cellId, sizeof(OduCellId));
385    return ROK;
386 }
387
388 /*******************************************************************
389  *
390  * @brief Handle Cell delete response from MAC
391  *
392  * @details
393  *
394  *    Function : DuProcMacCellDeleteRsp
395  *
396  *    Functionality: Handle Cell delete response from MAC
397  *
398  * @params[in] Pointer to MacCellDeleteRsp and Pst
399  * @return ROK     - success
400  *         RFAILED - failure
401  *
402  * ****************************************************************/
403
404 uint8_t DuProcMacCellDeleteRsp(Pst *pst, MacCellDeleteRsp *deleteRsp)
405 {
406    uint8_t ret = ROK;
407    uint16_t cellIdx=0, pfIdx=0;
408    DuPagInfoList *pagInfoLLFromPF=NULLP;
409
410    if(deleteRsp)
411    {
412       if(deleteRsp->status == SUCCESSFUL)
413       {
414          GET_CELL_IDX(deleteRsp->cellId, cellIdx);
415          DU_LOG("\nINFO   -->  DU APP : MAC CELL Delete Response : SUCCESS [CELL IDX : %d]", deleteRsp->cellId);
416          if(duCb.actvCellLst[cellIdx] && (duCb.actvCellLst[cellIdx]->cellId == deleteRsp->cellId))
417          {
418             for(pfIdx =0; pfIdx < MAX_SFN; pfIdx++)
419             {
420                pagInfoLLFromPF = findPagingInfoFromMap(pfIdx, &(duCb.actvCellLst[cellIdx]->pagingInfoMap));
421                if(pagInfoLLFromPF)
422                {   
423                   cmHashListDelete(&(duCb.actvCellLst[cellIdx]->pagingInfoMap), (PTR)pagInfoLLFromPF);
424                   DU_FREE(pagInfoLLFromPF, sizeof(DuPagInfoList));
425                }
426             }
427
428             memset(duCb.actvCellLst[cellIdx], 0, sizeof(DuCellCb));
429             gConfigInfo.gCellStatus = CELL_DOWN;
430
431 #ifdef O1_ENABLE
432             DU_LOG("\nINFO   -->  DU APP : Raise cell down alarm for cell id=%d", deleteRsp->cellId);
433             raiseCellAlrm(CELL_DOWN_ALARM_ID, deleteRsp->cellId);
434             setCellOpState(deleteRsp->cellId, DISABLED, INACTIVE);
435 #endif
436
437             duCb.numActvCells--;
438             duCb.numCfgCells--;
439             DU_FREE(duCb.actvCellLst[cellIdx], sizeof(DuCellCb));
440
441          }
442          else
443          {
444             DU_LOG("\nERROR  -->  DU APP : DuProcMacCellDeleteRsp(): CellId [%d] doesnot exist", deleteRsp->cellId);
445             ret = RFAILED;
446          }
447       }
448       else
449       {
450          DU_LOG("\nERROR  -->  DU APP : DuProcMacCellDeleteRsp(): MAC CELL Delete Response : FAILED\
451          [CELL IDX : %d]", deleteRsp->cellId);
452          ret = RFAILED;
453       }
454       DU_FREE_SHRABL_BUF(pst->region, pst->pool, deleteRsp, sizeof(MacCellDeleteRsp));
455    }
456    else
457    {
458       DU_LOG("\nERROR  -->  DU APP : DuProcMacCellDeleteRsp(): Received MAC cell delete response is NULL");
459       ret = RFAILED;
460    }
461    return ret;
462 }
463
464 /*******************************************************************
465  *
466  * @brief Sending Cell Delete Req To Mac
467  *
468  * @details
469  *
470  *    Function : sendCellDeleteReqToMac
471  *
472  *    Functionality:
473  *     sending Cell Delete Req To Mac
474  *
475  *  @params[in]    uint16_t cellId
476  *  @return ROK     - success
477  *          RFAILED - failure
478  *
479  *
480  *****************************************************************/
481
482 uint8_t sendCellDeleteReqToMac(uint16_t cellId)
483 {
484    Pst pst;
485    uint8_t ret=ROK;
486    MacCellDeleteReq *cellDelete = NULLP;
487    
488    DU_ALLOC_SHRABL_BUF(cellDelete, sizeof(MacCellDeleteReq));
489    if(cellDelete)
490    {
491       cellDelete->cellId = cellId;
492       FILL_PST_DUAPP_TO_MAC(pst, EVENT_MAC_CELL_DELETE_REQ);
493
494       DU_LOG("\nINFO   -->  DU APP : Sending Cell Delete Request to MAC");  
495       /* Processing one Cell at a time to MAC */
496       ret = (*packMacCellDeleteReqOpts[pst.selector])(&pst, cellDelete);
497       if(ret == RFAILED)
498       {
499          DU_LOG("\nERROR  -->  DU APP : sendCellDeleteReqToMac(): Failed to send Cell delete Req to MAC");
500          DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, cellDelete, sizeof(MacCellDeleteReq));
501       }
502    }
503    else
504    {
505       DU_LOG("\nERROR  -->   DU APP : sendCellDeleteReqToMac(): Failed to allocate memory"); 
506       ret = RFAILED;
507    }
508    return ret;
509 }
510
511 /*******************************************************************
512  *
513  * @brief DU preocess Cell Delete Req to MAC 
514  *
515  * @details
516  *
517  *    Function : duSendCellDeletReq 
518  *
519  *    Functionality: DU process Cell Delete Req to MAC 
520  *
521  * @params[in] uint16_t cellId
522  * @return ROK     - success
523  *         RFAILED - failure
524  *
525  * ****************************************************************/
526
527 uint8_t duSendCellDeletReq(uint16_t cellId)
528 {
529    uint16_t cellIdx = 0;
530    DU_LOG("\nINFO   -->  DU APP : Processing Cell Delete Request ");
531    GET_CELL_IDX(cellId, cellIdx);
532
533    if(duCb.actvCellLst[cellIdx] == NULLP)
534    {
535       DU_LOG("\nERROR  -->  DU APP : duSendCellDeletReq(): CellId[%d] is not found", cellId);
536       return RFAILED;
537    }
538    
539    if(duCb.actvCellLst[cellIdx]->cellId != cellId)
540    {
541       DU_LOG("\nERROR  -->  DU APP : duSendCellDeletReq(): CellId[%d] is not found", cellId);
542       return RFAILED;
543
544    }  
545    
546    if(duCb.actvCellLst[cellIdx]->cellStatus != DELETION_IN_PROGRESS)
547    {
548       DU_LOG("\nERROR  -->  DU APP : duSendCellDeletReq(): CellStatus[%d] of cellId[%d] is not correct.\
549       Expected CellStatus is DELETION_IN_PROGRESS",duCb.actvCellLst[cellIdx]->cellStatus, cellId);
550       return RFAILED;  
551    }
552
553    if(duBuildAndSendMacCellStop(cellId) == RFAILED)
554    {
555       DU_LOG("\nERROR  -->  DU APP : duSendCellDeletReq(): Failed to build and send cell stop request to MAC for\
556             cellId[%d]",cellId);
557       return RFAILED;
558    }
559
560    return ROK;
561 }
562
563 /*******************************************************************
564  * @brief Free PCCH PDU structure
565  *
566  * @details
567  *
568  *    Function : freePcchPdu
569  *
570  *    Functionality:  Free PCCH PDU structure
571  *
572  * @params[in] PCCH_Message_t *pcchMsg 
573  *
574  * @return void
575  *
576  * ****************************************************************/
577 void freePcchPdu(PCCH_Message_t *pcchMsg)
578 {
579    PagingRrc_t *pagingMsg = NULLP;
580    uint8_t recordIdx = 0;
581
582    if(pcchMsg != NULLP)
583    {
584       if(pcchMsg->message.choice.c1  != NULLP)
585       {
586          pagingMsg = pcchMsg->message.choice.c1->choice.paging;
587          if(pagingMsg != NULLP)   
588          {
589             if(pagingMsg->pagingRecordList)
590             {
591                if(pagingMsg->pagingRecordList->list.array != NULLP)
592                {
593                   for(recordIdx = 0; recordIdx <  pagingMsg->pagingRecordList->list.count; recordIdx++)
594                   {
595                      if(pagingMsg->pagingRecordList->list.array[recordIdx] != NULLP)
596                      {
597                         DU_FREE(pagingMsg->pagingRecordList->list.array[recordIdx]->ue_Identity.choice.ng_5G_S_TMSI.buf,\
598                                  pagingMsg->pagingRecordList->list.array[recordIdx]->ue_Identity.choice.ng_5G_S_TMSI.size);
599                         DU_FREE(pagingMsg->pagingRecordList->list.array[recordIdx], sizeof(PagingRecord_t));
600                      }
601                   }
602                   DU_FREE(pagingMsg->pagingRecordList->list.array, pagingMsg->pagingRecordList->list.size);
603                }
604                DU_FREE(pagingMsg->pagingRecordList, sizeof(PagingRecordList_t));
605             }
606             DU_FREE(pcchMsg->message.choice.c1->choice.paging, sizeof(PagingRrc_t));
607          }
608          DU_FREE(pcchMsg->message.choice.c1 , sizeof(PCCH_MessageType_t)); 
609       }
610       DU_FREE(pcchMsg , sizeof(PCCH_Message_t));
611    }
612 }
613
614 /*******************************************************************
615  * @brief Builds the Pcch RRC PDU and forwards it to MAC
616  *
617  * @details
618  *
619  *    Function : BuildAndSendDlPcchIndToMac
620  *
621  *    Functionality: Builds the Pcch RRC PDU[As per Spec 38.331, Annexure A]
622  *                   and forwards it to MAC as Buffer along with PF and i_s
623  *
624  * @params[in] uint16_t cellId, uint16_t pf, uint8_t i_s,CmLListCp *pageUeLL
625  *
626  * @return ROK     - success
627  *         RFAILED - failure
628  *
629  * ****************************************************************/
630 uint8_t BuildAndSendDlPcchIndToMac(uint16_t cellId, uint16_t pf, uint8_t i_s, CmLListCp *pageUeLL)
631 {
632    CmLList        *node = NULLP, *next = NULLP;
633    DuPagUeRecord  *ueRecord = NULLP;
634    PCCH_Message_t *pcchMsg = NULLP;
635    asn_enc_rval_t encRetVal;
636    PagingRrc_t    *pagingMsg = NULLP;
637    DlPcchInd     *macPcchInd = NULLP;
638    uint8_t        recordIdx = 0, ret = RFAILED;
639    
640    /*As per 38.473 Sec 9.3.1.39,5G-S-TMSI :48 Bits >>  Bytes and 0 UnusedBits */
641    uint8_t         totalByteInTmsi = 6, unusedBitsInTmsi = 0;
642
643    if(pageUeLL == NULLP || pageUeLL->count == 0)
644    {
645       DU_LOG("\nERROR  -->  DU APP: UE Page Record LL is empty");
646       return RFAILED;
647    }
648
649    while(true)
650    {
651       memset(&encRetVal, 0, sizeof(asn_enc_rval_t));
652       DU_ALLOC(pcchMsg , sizeof(PCCH_Message_t));
653       if(pcchMsg == NULLP)
654       {
655          DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(): (pccchMsg) Memory Alloction failed!");
656          break;
657       }
658       pcchMsg->message.present = PCCH_MessageType_PR_c1;
659       DU_ALLOC(pcchMsg->message.choice.c1 , sizeof(PCCH_MessageType_t));
660       if(pcchMsg->message.choice.c1 == NULLP)
661       {
662          DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(); (C1) Memory Alloction failed!");
663          break;
664       }
665       pcchMsg->message.choice.c1->present = PCCH_MessageType__c1_PR_paging;
666       DU_ALLOC(pcchMsg->message.choice.c1->choice.paging, sizeof(PagingRrc_t));
667
668       pagingMsg = pcchMsg->message.choice.c1->choice.paging;
669       if(pagingMsg == NULLP)
670       {
671          DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(); (Paging) Memory Alloction failed!");
672          break;
673       }
674       DU_ALLOC(pagingMsg->pagingRecordList, sizeof(PagingRecordList_t));
675       if(pagingMsg->pagingRecordList == NULLP)
676       {
677          DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(); (Paging Record List) Memory Alloction failed!");
678          break;
679       }
680
681       pagingMsg->pagingRecordList->list.count = pageUeLL->count;
682
683        /*As per Spec 38.331, maxNrofPageRec : 32 [Maximum number of page records]*/
684       if(pageUeLL->count > MAX_PAGING_UE_RECORDS)
685       {
686          pagingMsg->pagingRecordList->list.count = MAX_PAGING_UE_RECORDS;
687       }
688
689       pagingMsg->pagingRecordList->list.size = pageUeLL->count * (sizeof(PagingRecord_t *));
690       DU_ALLOC(pagingMsg->pagingRecordList->list.array, pagingMsg->pagingRecordList->list.size);
691       if(pagingMsg->pagingRecordList->list.array == NULLP)
692       {
693          DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(); (Array) Memory Alloction failed!");
694          break;
695       }
696       for(recordIdx = 0; recordIdx < pageUeLL->count; recordIdx++)
697       {
698          DU_ALLOC(pagingMsg->pagingRecordList->list.array[recordIdx], sizeof(PagingRecord_t));
699          if(pagingMsg->pagingRecordList->list.array[recordIdx] == NULLP)
700          {
701             DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(); (Record) Memory Alloction failed!");
702             break;
703          }
704       }
705       recordIdx = 0;
706       node = pageUeLL->first;
707       while(node && (recordIdx < MAX_PAGING_UE_RECORDS))
708       {
709          next = node->next;
710          ueRecord = (DuPagUeRecord *)node->node;
711          if(ueRecord)
712          {
713             /*TODO : When Connected Mode Paging will be supported then I_RNTI will be introduced*/
714             pagingMsg->pagingRecordList->list.array[recordIdx]->ue_Identity.present = PagingUE_Identity_PR_ng_5G_S_TMSI;
715             pagingMsg->pagingRecordList->list.array[recordIdx]->ue_Identity.choice.ng_5G_S_TMSI.size = totalByteInTmsi*sizeof(uint8_t);
716             DU_ALLOC(pagingMsg->pagingRecordList->list.array[recordIdx]->ue_Identity.choice.ng_5G_S_TMSI.buf,\
717                   pagingMsg->pagingRecordList->list.array[recordIdx]->ue_Identity.choice.ng_5G_S_TMSI.size);
718             if(pagingMsg->pagingRecordList->list.array[recordIdx]->ue_Identity.choice.ng_5G_S_TMSI.buf == NULLP)
719             {
720                DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(); (5gsTmsi buffer) Memory Allocation failed!");
721                break;
722             }
723             fillBitString(&pagingMsg->pagingRecordList->list.array[recordIdx]->ue_Identity.choice.ng_5G_S_TMSI,\
724                   unusedBitsInTmsi, totalByteInTmsi, ueRecord->sTmsi);
725             recordIdx++;
726          }
727
728          if(duDelNodeFromLList(pageUeLL, node) == ROK)
729              DU_FREE(ueRecord, sizeof(DuPagUeRecord));
730          node = next;
731       }
732       if(node != NULLP && (recordIdx < MAX_PAGING_UE_RECORDS))
733       {
734          /*This leg is hit because Whole UE REcord List was not traversed as
735           * some issue happened thus exiting the main while*/
736          break;
737       }
738       xer_fprint(stdout, &asn_DEF_PCCH_Message, pcchMsg);
739       memset(encBuf, 0, ENC_BUF_MAX_LEN);
740       encBufSize = 0;
741        /* Encode the PCCH RRC PDU as APER */
742       encRetVal = uper_encode(&asn_DEF_PCCH_Message, 0, pcchMsg, PrepFinalEncBuf,\
743             encBuf);
744
745       if(encRetVal.encoded == ENCODE_FAIL)
746       {
747          DU_LOG("\nERROR  -->  F1AP : Could not encode Paging structure (at %s)\n",\
748                encRetVal.failed_type ? encRetVal.failed_type->name : "unknown");
749          break;
750       }
751       else
752       {
753          DU_LOG("\nDEBUG  -->  F1AP : Created APER encoded buffer for RRC PDU for Pcch indication \n");
754          
755          DU_ALLOC_SHRABL_BUF(macPcchInd, sizeof(DlPcchInd));
756          if(macPcchInd == NULLP)
757          {
758             DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(); (macPcchInd) Memory Alloction failed!");
759             break;
760          }
761          
762          macPcchInd->cellId = cellId;
763          macPcchInd->pf = pf;
764          macPcchInd->i_s = i_s;
765          macPcchInd->pduLen = encBufSize;
766          DU_ALLOC_SHRABL_BUF(macPcchInd->pcchPdu, macPcchInd->pduLen);
767          if(macPcchInd->pcchPdu == NULLP)
768          {
769             DU_LOG("\nERROR  -->  DU APP: BuildAndSendDlPcchIndToMac(); (PcchPDU) Memory Alloction failed!");
770             break;
771          }
772          memcpy(macPcchInd->pcchPdu, encBuf, macPcchInd->pduLen);
773          ret = sendDlPcchIndToMac(macPcchInd);
774          if(ret != ROK)
775          {
776             DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, macPcchInd->pcchPdu, macPcchInd->pduLen);
777             DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, macPcchInd, sizeof(DlPcchInd));
778             break;
779          }
780       }
781       ret = ROK;
782       break;
783    }
784    freePcchPdu(pcchMsg);
785    return ret;
786 }
787
788 /*******************************************************************
789  * @brief Keeping the record of Paging having a particular SFN and index associated 
790  *
791  * @details
792  *
793  *    Function : insertPagingRecord 
794  *
795  *    Functionality:  Insert record of Paging assoc with particular SFN and index associated 
796  *
797  * @params[in] DuCellCb* cellCb, uint16_t iterations
798  *             DuPagingMsg  rcvdF1apPagingParam
799  *
800  * @return ROK     - success
801  *         RFAILED - failure
802  *
803  * ****************************************************************/
804 uint8_t insertPagingRecord(DuCellCb* cellCb, DuPagingMsg *rcvdF1apPagingParam, uint16_t iterations)
805 {
806    uint16_t maxIterations = 0; 
807    DuPagInfoList *pagInfoLLFromPF = NULLP;
808    DuPagUeList  *pageUeLL = NULLP;
809    DuPagUeRecord *ueRecord = NULLP;
810
811 #if 0
812    printPageList(&(cellCb->pagingInfoMap));
813 #endif
814
815    /*MAX Iteration : A UE can be paged at every T frames thus MAX determines
816     *how many Paging Frame(s) can be considered for Paging this UE*/
817    maxIterations = MAX_SFN/rcvdF1apPagingParam->T;
818    if(iterations >= maxIterations)
819    {
820       DU_LOG("\nERROR  --> DU APP: MAX Iterations reached for UEID:%d, thus Paging is dropped!", rcvdF1apPagingParam->pagUeId);
821       return RFAILED;
822    }
823
824    /*[Step1]: Extracting the PF from the HasMap between PF and PagingInfoList*/
825    pagInfoLLFromPF = findPagingInfoFromMap(rcvdF1apPagingParam->pagingFrame, &(cellCb->pagingInfoMap));
826    if(pagInfoLLFromPF != NULLP)
827    {
828       /*[Step2]: Extracting the PageInfo List for the Paging Indices(i_s)*/
829       pageUeLL = handlePageInfoLL(rcvdF1apPagingParam->pagingFrame, rcvdF1apPagingParam->i_s, \
830             &(pagInfoLLFromPF->pagInfoList), CREATE);
831
832       if(pageUeLL != NULLP)
833       {
834          /*[Step3]: Check whether MAX UE Record against this PF and i_s has reached(Spec 38.331, Annexure A)*/
835          if(pageUeLL->pagUeList.count < MAX_PAGING_UE_RECORDS)
836          {
837             /*[Step4]: Insert the Paging Record to the end of the UE record List*/
838             ueRecord = handlePageUeLL(rcvdF1apPagingParam->pagUeId, rcvdF1apPagingParam->sTmsi,\
839                   &(pageUeLL->pagUeList), CREATE);
840
841             if(ueRecord == NULLP)
842             {
843                DU_LOG("\nERROR  --> DU APP: Unable to create UE Record in PagingList");
844                return RFAILED;
845             }
846             DU_LOG("\nDEBUG  --> DU APP: UE Record created successfully in PagingList");
847             return ROK;
848          }
849          else
850          {
851             /*Since MAX Page record has reached for this PF thus calculating and
852              *moving this UE to next Paging Cycle*/
853             DU_LOG("\nINFO   --> DU APP: Max Page Record reached for PagingFrame:%d",rcvdF1apPagingParam->pagingFrame);
854             rcvdF1apPagingParam->pagingFrame = ((rcvdF1apPagingParam->pagingFrame + rcvdF1apPagingParam->T) % MAX_SFN);
855             iterations++;
856
857             return insertPagingRecord(cellCb, rcvdF1apPagingParam, iterations);
858          }
859       }
860    }
861    /*Reaching here means that PF has no entry in the PageLists,
862     *Thus creating, Updating and inseritng the Paging Map, List and UE record.*/
863
864    DU_ALLOC(pagInfoLLFromPF, sizeof(DuPagInfoList));
865
866    if(pagInfoLLFromPF == NULLP)
867    {
868       DU_LOG("\nERROR  --> DU APP: PageInfo Map allocation failed.");
869       return RFAILED;
870    }
871    pagInfoLLFromPF->pf = rcvdF1apPagingParam->pagingFrame;
872    pageUeLL = handlePageInfoLL(rcvdF1apPagingParam->pagingFrame, rcvdF1apPagingParam->i_s, &(pagInfoLLFromPF->pagInfoList), CREATE);
873    ueRecord = handlePageUeLL(rcvdF1apPagingParam->pagUeId, rcvdF1apPagingParam->sTmsi, &(pageUeLL->pagUeList), CREATE);
874    if(cmHashListInsert(&(cellCb->pagingInfoMap), (PTR)pagInfoLLFromPF, (uint8_t *)&(pagInfoLLFromPF->pf), sizeof(uint16_t)) == RFAILED)
875    {
876       DU_LOG("\nERROR  --> DU APP: Hash Map Insertion Failed for PF:%d.",rcvdF1apPagingParam->pagingFrame);
877    }
878
879 #if 0
880    printPageList(&(cellCb->pagingInfoMap));
881 #endif
882
883    return ROK;
884
885
886 }
887
888 /*******************************************************************
889  * @brief Calculate and fill paging information of a UE belongs to a particular cell
890  *
891  * @details
892  *
893  *    Function : calcAndFillPagingInfoInCellCb
894  *
895  *    Functionality: Calculate PO and i_s and 
896  *                   fill paging information of a UE in DuCellCb
897  *
898  * @params[in] DuCellCb* cellCb, uint8_t pagUeId, 
899  *             DuPagingMsg  rcvdF1apPagingParam
900  *
901  * @return ROK     - success
902  *         RFAILED - failure
903  *
904  * ****************************************************************/
905 uint8_t calcAndFillPagingInfoInCellCb(DuCellCb* cellCb, DuPagingMsg *rcvdF1apPagingParam)
906 {
907    uint8_t ns = 0;
908    uint16_t T=0, N=0, pagingFrame = 0, n = 0;
909    uint16_t currentSfn = 0, sfn = 0, newSfn = 0;
910    PcchCfg   duPcchCfg;
911
912    if(cellCb)
913    {
914       /* calculate paging frame and paging offset */
915       duPcchCfg = duCfgParam.sib1Params.srvCellCfgCommSib.dlCfg.pcchCfg;
916       rcvdF1apPagingParam->pagingFrameOffset = duPcchCfg.pageFrameOffset;
917       ns = duPcchCfg.ns;      
918
919       /*
920        * Fill the Value of T (DRX cycle of the UE)
921        * T = min(UE Specific DRX value allocated by upper layers, default DRX
922        * broadcast in System Information) */
923       if((rcvdF1apPagingParam->pagingDrxPres) && (duPcchCfg.dfltPagingCycle > rcvdF1apPagingParam->pagingDrx))
924       {
925          T = rcvdF1apPagingParam->pagingDrx;
926       } 
927       else
928       {
929          T = duPcchCfg.dfltPagingCycle;
930       }
931       rcvdF1apPagingParam->T = T;
932
933        /* N= number of total paging frames in T */
934
935       switch(duPcchCfg.nAndPagingFrmOffsetType)
936       {
937          case PCCH_Config__nAndPagingFrameOffset_PR_oneT:
938             N = T;
939             break;
940          case PCCH_Config__nAndPagingFrameOffset_PR_halfT:
941             N = T/2;
942             break;
943          case PCCH_Config__nAndPagingFrameOffset_PR_quarterT:
944             N = T/4;
945             break;
946          case PCCH_Config__nAndPagingFrameOffset_PR_oneEighthT:
947             N = T/8;
948             break;
949          case PCCH_Config__nAndPagingFrameOffset_PR_oneSixteenthT:
950             N = T/16;
951             break;
952          default:
953             N = T;
954             break;
955       }
956
957        /* calculate the Value of pagingFrame */
958       /*Refer: 38.304 Sec 7.1: (SFN + PF_offset) mod T = (T div N)*(UE_ID mod N)*/
959       //RHS of above formula
960       pagingFrame = (T / N) * ((rcvdF1apPagingParam->pagUeId) % N);
961
962       //LHS of above formula
963       if(pagingFrame)
964       {
965          pagingFrame = (pagingFrame - rcvdF1apPagingParam->pagingFrameOffset)%T;
966       }
967       else /*Paging Frame = 0 so thus PF will be calculated on Paging Cycle*/
968       {
969          pagingFrame = (T - rcvdF1apPagingParam->pagingFrameOffset)%T;
970       }
971
972       /*Paging Frame(SFN for Paging) has to be determined from current SFN. */
973       /*For eg: If T =128, PF(Calculated above) = 20; SFN can be 20,148,276,...
974        * If currSFN is running as 200 then (newSFN % T) == (T/N)*(UE_ID%N)
975        *Thus SFN at which paging has to be sent needs to be delayed and newSFN = 276*/
976
977       currentSfn = cellCb->currSlotInfo.sfn;
978
979       /*Multiplication Factor(x) to find the next best SFN to process paging*/
980
981       /*Below calculation will determine in which nth cycle of T (DRX cycle),new PF
982        * may fall(Delayed one)*/
983       if(currentSfn > pagingFrame)
984       {
985          n  = ((currentSfn - pagingFrame) / T) + 1;
986       }
987       else
988       {
989          n  = ((pagingFrame - currentSfn) / T) + 1;
990       }
991
992       newSfn = pagingFrame + T * n;
993
994       /*When pagingFrame is future from currSFN then pagingFrame will be used 
995        * else pagingFrame is delayed thus newSFN will be used.*/
996       if(currentSfn <= pagingFrame)
997       {
998          if(pagingFrame > currentSfn + PAGING_SCHED_DELTA)
999          {
1000             sfn = pagingFrame;
1001          }
1002          else
1003          {
1004             sfn = newSfn;
1005          }
1006       }
1007       else
1008       {
1009          
1010          if(newSfn > currentSfn + PAGING_SCHED_DELTA)
1011          {
1012             sfn = newSfn;
1013          }
1014          else /*If newSFN is near to currSFN then delay it more by T*/
1015          {
1016             newSfn = newSfn + T;
1017             sfn = newSfn;
1018          }
1019       }
1020       rcvdF1apPagingParam->pagingFrame =  (sfn % MAX_SFN);
1021       rcvdF1apPagingParam->i_s = ((uint32_t)(floor(rcvdF1apPagingParam->pagUeId / N)) % ns);
1022
1023       memcpy(&cellCb->tmpPagingInfoOfUe, rcvdF1apPagingParam, sizeof(DuPagingMsg));
1024    }
1025    else
1026    {
1027       DU_LOG("\nINFO  --> DU APP : calcAndFillPagingInfoInCellCb(): Received null pointer");
1028       return RFAILED;
1029    }
1030    return ROK;
1031 }
1032
1033 /*******************************************************************
1034  * @brief Paging Processing on a particular cell 
1035  *
1036  * @details
1037  *
1038  *    Function : processPagingMsg
1039  *
1040  *    Functionality: Process Paging on a particular cell 
1041  *
1042  * @params[in] uint16_t cellId
1043  *             DuPagingMsg  rcvdF1apPagingParam
1044  *
1045  * @return ROK     - success
1046  *         RFAILED - failure
1047  *
1048  * ****************************************************************/
1049 uint8_t processPagingMsg(uint16_t cellId, DuPagingMsg *rcvdF1apPagingParam)
1050 {
1051    uint16_t cellIdx = 0, iteration = 0;
1052
1053    GET_CELL_IDX(cellId, cellIdx);
1054
1055    if(duCb.actvCellLst[cellIdx] == NULLP || duCb.actvCellLst[cellIdx]->cellId != cellId)
1056    {
1057       DU_LOG("\nERROR  -->  DU APP : processPagingMsg(): CellId[%d] is not found", cellId);
1058       return RFAILED;
1059    }
1060    
1061    if(calcAndFillPagingInfoInCellCb(duCb.actvCellLst[cellIdx], rcvdF1apPagingParam) != ROK)
1062    {
1063       DU_LOG("\nERROR  --> DU APP : CellCb:%d not present to fill UE Paging Information",cellId);
1064       return RFAILED;
1065    }
1066    if(insertPagingRecord(duCb.actvCellLst[cellIdx], rcvdF1apPagingParam, iteration) != ROK)
1067    {
1068       DU_LOG("\nERROR  --> DU APP : Insertion Failed ofUE Paging Information");
1069       return RFAILED;
1070    }
1071    return ROK;
1072
1073 }
1074
1075 /*******************************************************************
1076  *
1077  * @brief DU build and send dl broacast req  and send it to MAC
1078  *
1079  * @details
1080  *
1081  *    Function : duBuildAndSendDlBroadcastReq
1082  *
1083  *    Functionality: DU build and send dl broacast req and send to MAC
1084  *                   
1085  *
1086  * @params[in] cellId, crnti 
1087  * @return ROK     - success
1088  *         RFAILED - failure
1089  *
1090  * ****************************************************************/
1091
1092 uint8_t duBuildAndSendDlBroadcastReq()
1093 {
1094    Pst pst;
1095    uint8_t ret =ROK;
1096    MacDlBroadcastReq *dlBroadcast=NULLP;
1097
1098    DU_LOG("\nDEBUG  -->  DU_APP : Building Dl broadcast request");
1099
1100    DU_ALLOC_SHRABL_BUF(dlBroadcast, sizeof(MacDlBroadcastReq));
1101    if(dlBroadcast)
1102    {
1103       /*TODO - fill MAC DL Broadcast Request*/
1104       
1105       FILL_PST_DUAPP_TO_MAC(pst, EVENT_MAC_DL_BROADCAST_REQ);
1106
1107       DU_LOG("\nDEBUG  -->  DU_APP: Sending Dl broadcast  Request to MAC ");
1108       ret = (*packMacDlBroadcastReqOpts[pst.selector])(&pst, dlBroadcast);
1109       if(ret == RFAILED)
1110       {
1111          DU_LOG("\nERROR  -->  DU_APP: sendDlBroadcastReqToMac(): Failed to send Dl broadcast  Req to MAC");
1112          DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, dlBroadcast, sizeof(MacDlBroadcastReq));
1113       }
1114    }
1115    else
1116    {
1117       DU_LOG("\nERROR  -->   DU_APP: sendDlBroadcastReqToMac(): Failed to allocate memory"); 
1118       ret =  RFAILED;
1119    }
1120
1121    return ret;
1122 }
1123
1124 /**********************************************************************
1125   End of file
1126  **********************************************************************/