[Epic-ID: ODUHIGH-462][Task-ID: ODUHIGH-472] Implementation of drx timer
[o-du/l2.git] / src / cu_stub / cu_f1ap_msg_hdl.c
index 4f2b34f..4920f8b 100644 (file)
 #include "CNUEPagingIdentity.h"
 #include "PagingCell-Item.h"
 #include "UL-DCCH-Message.h"
+#include "DRX-ConfigRrc.h"
 
 #include "cu_stub_sctp.h"
 #include "cu_stub_egtp.h"
@@ -1513,8 +1514,27 @@ uint8_t  BuildDLRRCContainer(CuUeCb *ueCb, uint8_t rrcMsgType, RRCContainer_t *rr
    }
    else if(rrcMsgType == RRC_SETUP_COMPLETE)
    {
-      DU_LOG("\nINFO --> F1AP : Sending Security mode command");
-      char secModeBuf[9]={0x00, 0x02, 0x22, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00};
+      DU_LOG("\nINFO --> F1AP : Sending NAS Security mode command");
+      char secModeBuf[30]={0x00, 0x02, 0x2e, 0x82, 0xaf, 0xc0, 0x7d, 0x1c, 0x4e, 0xfc, 0x80, 0x0f, 0xc0, 
+                          0x0b, 0xa0, 0x20, 0x40, 0x9e, 0x0e, 0x1e, 0x0e, 0x1c, 0x26, 0xc0, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00};
+      bufLen =30;
+      rrcContainer->size = bufLen;
+      CU_ALLOC(rrcContainer->buf, rrcContainer->size);
+      if(rrcContainer->buf != NULLP)
+      {     
+         memset(rrcContainer->buf, 0, bufLen);
+         memcpy(rrcContainer->buf, secModeBuf, bufLen);
+      }
+      else
+      {     
+         DU_LOG("\nERROR  -->  F1AP : Memory allocation failure for RRC Container buffer");
+         ret = RFAILED;
+      }     
+   }
+   else if(rrcMsgType == NAS_SECURITY_MODE_COMPLETE)
+   {
+      DU_LOG("\nINFO --> F1AP : Sending RRC Security mode command");
+      char secModeBuf[9]={0x00, 0x03, 0x22, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00};
       bufLen =9;
       rrcContainer->size = bufLen;
       CU_ALLOC(rrcContainer->buf, rrcContainer->size);
@@ -1529,11 +1549,11 @@ uint8_t BuildDLRRCContainer(CuUeCb *ueCb, uint8_t rrcMsgType, RRCContainer_t *rr
          ret = RFAILED;
       }
    }
-   else if(rrcMsgType == SECURITY_MODE_COMPLETE)
+   else if(rrcMsgType == RRC_SECURITY_MODE_COMPLETE)
    {
       /*Hardcoded RRC Container from reference logs*/
       DU_LOG("\nINFO --> F1AP : Sending Registration accept");
-      char buf[14] ={0x00, 0x03, 0x2a, 0x80, 0xaf, 0xc0, 0x08, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00};
+      char buf[14] ={0x00, 0x04, 0x2a, 0x80, 0xaf, 0xc0, 0x08, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00};
       bufLen =14;
       rrcContainer->size = bufLen;
       CU_ALLOC(rrcContainer->buf, rrcContainer->size);
@@ -1767,8 +1787,11 @@ uint8_t setDlRRCMsgType(CuUeCb *ueCb)
       case RRC_SETUP_COMPLETE:
          rrcMsgType = RRC_SETUP_COMPLETE;
          break;
-      case SECURITY_MODE_COMPLETE:
-         rrcMsgType = SECURITY_MODE_COMPLETE;
+      case NAS_SECURITY_MODE_COMPLETE:
+         rrcMsgType = NAS_SECURITY_MODE_COMPLETE;
+         break;
+      case RRC_SECURITY_MODE_COMPLETE:
+         rrcMsgType = RRC_SECURITY_MODE_COMPLETE;
          break;
       case REGISTRATION_COMPLETE:
          rrcMsgType = REGISTRATION_COMPLETE;
@@ -1785,6 +1808,187 @@ uint8_t setDlRRCMsgType(CuUeCb *ueCb)
    return rrcMsgType;   
 }
 
+#ifdef NR_DRX
+/*******************************************************************
+ *
+ * @brief fill long cycle offset value of drx
+ *
+ * @details
+ *
+ *    Function : fillLongCycleOffsetValue
+ *
+ *    Functionality: fill long cycle offset value of drx
+ *
+ * @params[in] DrxLongCycleStartOffset  drxLongCycleStartOffset,
+ * struct DRX_ConfigRrc__drx_LongCycleStartOffset recvedLongCycleOffsetVal 
+ *
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+void fillLongCycleOffsetValue(DrxLongCycleStartOffset *drxLongCycleStartOffset, struct DRX_ConfigRrc__drx_LongCycleStartOffset *recvedLongCycleOffsetVal)
+{
+
+   drxLongCycleStartOffset->drxLongCycleStartOffsetChoice = recvedLongCycleOffsetVal->present;
+   switch(recvedLongCycleOffsetVal->present)
+   {
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms10:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms10;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms20:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms20;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms32:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms32;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms40:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms40;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms60:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms60;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms64:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms64;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms70:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms70;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms80:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms80;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms128:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms128;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms160:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms160;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms256:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms256;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms320:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms320;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms512:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms512;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms640:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms640;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms1024:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms1024;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms1280:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms1280;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms2048:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms2048;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms2560:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms2560;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms5120:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms5120;
+            break;
+         }
+      case DRX_ConfigRrc__drx_LongCycleStartOffset_PR_ms10240:
+         {
+            drxLongCycleStartOffset->drxLongCycleStartOffsetVal = recvedLongCycleOffsetVal->choice.ms10240;
+            break;
+         }
+      default :
+         break;
+   }
+}
+
+/*******************************************************************
+ *
+ * @brief Extract configuration from DRX_ConfigRrc 
+ *    and store the drx configuration in UeCb
+ *
+ * @details
+ *
+ *    Function : storeDrxCfgInUeCb 
+ *
+ *    Functionality: Store drx configuration in UeCb 
+ *
+ * @params[in] (struct DRX_ConfigRrc *setup, DrxCfg *drxCfg) 
+ *
+ * @return void 
+ * ****************************************************************/
+void storeDrxCfgInUeCb(struct DRX_ConfigRrc *drxSetup, DrxCfg *drxCfg)
+{
+   switch(drxSetup->drx_onDurationTimer.present)
+   {
+      case DRX_ConfigRrc__drx_onDurationTimer_PR_NOTHING:
+         break;
+      case DRX_ConfigRrc__drx_onDurationTimer_PR_milliSeconds:
+         {
+            drxCfg->drxOnDurationTimer.onDurationTimerValInMs = true;
+            drxCfg->drxOnDurationTimer.onDurationtimerValue.milliSeconds=drxSetup->drx_onDurationTimer.choice.milliSeconds;
+            break;
+         }
+      case DRX_ConfigRrc__drx_onDurationTimer_PR_subMilliSeconds:
+         {
+            drxCfg->drxOnDurationTimer.onDurationTimerValInMs = false;
+            drxCfg->drxOnDurationTimer.onDurationtimerValue.subMilliSeconds = drxSetup->drx_onDurationTimer.choice.subMilliSeconds;
+            break;
+         }
+   }
+   fillLongCycleOffsetValue(&drxCfg->drxLongCycleStartOffset, &drxSetup->drx_LongCycleStartOffset);
+   drxCfg->drxInactivityTimer = drxSetup->drx_InactivityTimer;
+   drxCfg->drxHarqRttTimerDl = drxSetup->drx_HARQ_RTT_TimerDL;
+   drxCfg->drxHarqRttTimerUl = drxSetup->drx_HARQ_RTT_TimerUL;
+   drxCfg->drxRetransmissionTimerDl = drxSetup->drx_RetransmissionTimerDL;
+   drxCfg->drxRetransmissionTimerUl = drxSetup->drx_RetransmissionTimerUL;
+   drxCfg->drxSlotOffset = drxSetup->drx_SlotOffset;
+   if(drxSetup->shortDRX) 
+   {
+      drxCfg->shortDrxPres=true;
+      drxCfg->shortDrx.drxShortCycle = drxSetup->shortDRX->drx_ShortCycle;
+      drxCfg->shortDrx.drxShortCycleTimer = drxSetup->shortDRX->drx_ShortCycleTimer;
+   }
+   else
+      drxCfg->shortDrxPres=false;
+}
+#endif
+
 /*******************************************************************
  *
  * @brief Extract configuration from CellGroupConfig
@@ -1814,6 +2018,9 @@ uint8_t extractCellGroupConfig(CuUeCb *ueCb, CellGroupConfigRrc_t *cellGrpCfg)
    RLC_BearerConfig_t *rlcCfg = NULLP;
    RLC_Config_t *rlcLcCfg = NULLP;
    LogicalChannelConfig_t *macLcCfg = NULLP;
+#ifdef NR_DRX
+   DrxCfg    drxCfg;
+#endif
 
    if(ueCb == NULLP)
    {
@@ -1827,6 +2034,33 @@ uint8_t extractCellGroupConfig(CuUeCb *ueCb, CellGroupConfigRrc_t *cellGrpCfg)
       return RFAILED;
    }
 
+#ifdef NR_DRX
+   if(cellGrpCfg->mac_CellGroupConfig)
+   {
+      if(cellGrpCfg->mac_CellGroupConfig->drx_ConfigRrc)
+      {
+         switch(cellGrpCfg->mac_CellGroupConfig->drx_ConfigRrc->present)
+         {
+            case MAC_CellGroupConfig__drx_ConfigRrc_PR_NOTHING:
+               break;
+
+            case MAC_CellGroupConfig__drx_ConfigRrc_PR_setup:
+            {
+               if(cellGrpCfg->mac_CellGroupConfig->drx_ConfigRrc->choice.setup)
+               {
+                  ueCb->drxCfgPresent = true;  
+                  storeDrxCfgInUeCb(cellGrpCfg->mac_CellGroupConfig->drx_ConfigRrc->choice.setup, &ueCb->drxCfg);
+               }
+               break;
+            }
+
+            case MAC_CellGroupConfig__drx_ConfigRrc_PR_release:
+               break;
+         }
+      }
+   }
+#endif
+
    for(rbIdx = 0; rbIdx < cellGrpCfg->rlc_BearerToAddModList->list.count; rbIdx++)
    {
       srbFound = false;
@@ -1964,7 +2198,7 @@ uint8_t extractDuToCuRrcCont(CuUeCb *ueCb, OCTET_STRING_t rrcCont)
 
    if(rval.code == RC_FAIL || rval.code == RC_WMORE)
    {
-      DU_LOG("\nERROR  -->  F1AP : ASN decode failed");
+      DU_LOG("\nERROR  -->  F1AP : ASN decode failed in extractDuToCuRrcCont");
       return RFAILED;
    }
    printf("\n");
@@ -2660,6 +2894,7 @@ uint8_t BuildULTnlInfo(uint8_t duId, TnlInfo *ulUpTnlInfo, ULUPTNLInformation_To
  * ****************************************************************/
 uint8_t BuildDRBSetup(uint32_t duId, CuUeCb *ueCb, DRBs_ToBeSetup_List_t *drbSet)
 {
+   uint16_t snssaiIdx=0;
    uint8_t idx = 0, extIeIdx = 0;
    uint8_t elementCnt = 0, drbCnt = 0;
    uint8_t BuildQOSInforet = 0,BuildSNSSAIret = 0;
@@ -2728,12 +2963,13 @@ uint8_t BuildDRBSetup(uint32_t duId, CuUeCb *ueCb, DRBs_ToBeSetup_List_t *drbSet
       }
 
       /*SNSSAI*/
+      snssaiIdx = (idx% cuCb.numSnssaiSupported);
       if(ueCb->state != UE_HANDOVER_IN_PROGRESS)
          BuildSNSSAIret = BuildSNSSAI(&ueCb->drbList[ueCb->numDrb], &drbSetItem->qoSInformation.choice.\
-               choice_extension->value.choice.DRB_Information.sNSSAI, cuCb.snssaiList[0], FALSE);
+               choice_extension->value.choice.DRB_Information.sNSSAI, cuCb.snssaiList[snssaiIdx], FALSE);
       else
          BuildSNSSAIret = BuildSNSSAI(&ueCb->drbList[idx], &drbSetItem->qoSInformation.choice.\
-               choice_extension->value.choice.DRB_Information.sNSSAI, cuCb.snssaiList[0], TRUE);
+               choice_extension->value.choice.DRB_Information.sNSSAI, NULLP, TRUE);
       if(BuildSNSSAIret != ROK)
       {
          DU_LOG("\nERROR  -->  F1AP : Failed to build SNSSAI Info in BuildDRBSetup");
@@ -5268,7 +5504,7 @@ uint8_t BuildSchedulingReqConfig(struct SchedulingRequestConfig *schedulingReque
  * ****************************************************************/
 uint8_t BuildMacCellGrpCfg(MAC_CellGroupConfig_t *macCellGrpCfg)
 {
-   macCellGrpCfg->drx_Config = NULLP;
+   macCellGrpCfg->drx_ConfigRrc = NULLP;
    macCellGrpCfg->schedulingRequestConfig = NULLP;
    CU_ALLOC(macCellGrpCfg->schedulingRequestConfig, sizeof(struct SchedulingRequestConfig));
    if(!macCellGrpCfg->schedulingRequestConfig)
@@ -8739,7 +8975,7 @@ uint8_t fillCuToDuContainer(CuUeCb *ueCb, CUtoDURRCInformation_t *rrcMsg)
 {
    uint8_t elementCnt = 0;
    uint8_t ret = ROK;
-   uint8_t idx, idx2, rrcBufLen;
+   uint8_t idx;
 
    /* UE Capabulity RAT Container List */
    CU_ALLOC(rrcMsg->uE_CapabilityRAT_ContainerList, sizeof(UE_CapabilityRAT_ContainerList_t));
@@ -8807,7 +9043,42 @@ uint8_t fillCuToDuContainer(CuUeCb *ueCb, CUtoDURRCInformation_t *rrcMsg)
    }
    return ret;
 }
-
+/*******************************************************************
+ *
+ * @brief Build the drx cycle  
+ *
+ * @details
+ *
+ *    Function : BuildDrxCycle
+ *
+ *    Functionality: Build drx cycle IE
+ *
+ * @params[in] pointer to DRXCycle_t
+ *
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ ******************************************************************/
+uint8_t BuildDrxCycle(DRXCycle_t *drxCycle)
+{
+   drxCycle->longDRXCycleLength = LongDRXCycleLength_ms40;
+   CU_ALLOC(drxCycle->shortDRXCycleLength, sizeof(ShortDRXCycleLength_t));
+   if(!drxCycle->shortDRXCycleLength)
+   {
+      DU_LOG("\nERROR  -->  F1AP : Memory allocation failed for shortDRXCycleLength");
+      return RFAILED;
+   }
+   *(drxCycle->shortDRXCycleLength) = ShortDRXCycleLength_ms4;
+   
+   CU_ALLOC(drxCycle->shortDRXCycleTimer, sizeof(ShortDRXCycleTimer_t));
+   if(!drxCycle->shortDRXCycleTimer)
+   {
+      DU_LOG("\nERROR  -->  F1AP : Memory allocation failed for shortDRXCycleTimer");
+      return RFAILED;
+   }
+   *(drxCycle->shortDRXCycleTimer) = 4;
+   return ROK;
+}
 /*******************************************************************
  *
  * @brief Free CuToDuContainer 
@@ -8930,7 +9201,13 @@ uint8_t BuildAndSendUeContextSetupReq(uint32_t duId, CuUeCb *ueCb)
       if(ueCb->state == UE_HANDOVER_IN_PROGRESS)
          elementCnt = 7;
       else
+      {
+#ifdef NR_DRX
+         elementCnt = 12;
+#else
          elementCnt = 11;
+#endif
+      }
       ueSetReq->protocolIEs.list.count = elementCnt;
       ueSetReq->protocolIEs.list.size = elementCnt * sizeof(UEContextSetupRequestIEs_t *);
 
@@ -9020,6 +9297,18 @@ uint8_t BuildAndSendUeContextSetupReq(uint32_t duId, CuUeCb *ueCb)
 
       if(ueCb->state != UE_HANDOVER_IN_PROGRESS)
       {
+         /*Drx cycle*/
+#ifdef NR_DRX
+         idx++;
+         ueSetReq->protocolIEs.list.array[idx]->id     = ProtocolIE_ID_id_DRXCycle;
+         ueSetReq->protocolIEs.list.array[idx]->criticality    =       Criticality_ignore;
+         ueSetReq->protocolIEs.list.array[idx]->value.present = UEContextSetupRequestIEs__value_PR_DRXCycle;
+         if(BuildDrxCycle(&ueSetReq->protocolIEs.list.array[idx]->value.choice.DRXCycle) != ROK)
+         {
+            DU_LOG("\nERROR  -->  F1AP : Failed to build drx cycle");
+            break;
+         }
+#endif         
          /*Special Cells to be SetupList*/
          idx++;
          ueSetReq->protocolIEs.list.array[idx]->id     = ProtocolIE_ID_id_SCell_ToBeSetup_List;
@@ -9212,9 +9501,9 @@ uint8_t addDrbTunnels(uint32_t duId, uint8_t teId)
  *         RFAILED - failure
  *
  * ****************************************************************/
-uint8_t procDrbSetupList(uint32_t duId, DRBs_Setup_List_t *drbSetupList)
+uint8_t procDrbSetupList(uint32_t duId, CuUeCb *ueCb, DRBs_Setup_List_t *drbSetupList)
 {
-   uint8_t arrIdx = 0;
+   uint8_t arrIdx = 0, drbIdx = 0;
    uint32_t teId = 0;
    DRBs_Setup_ItemIEs_t *drbItemIe = NULLP;
 
@@ -9229,10 +9518,21 @@ uint8_t procDrbSetupList(uint32_t duId, DRBs_Setup_List_t *drbSetupList)
             teId  = extractTeId(&drbItemIe->value.choice.DRBs_Setup_Item.dLUPTNLInformation_ToBeSetup_List);
             if(teId > 0)
             {
-              if(addDrbTunnels(duId, teId)== ROK)
-              {
-                DU_LOG("\nDEBUG  --> EGTP: Tunnel Added for TeId %d", teId);
-              }
+               if(addDrbTunnels(duId, teId)== ROK)
+               {
+                  DU_LOG("\nDEBUG  --> EGTP: Tunnel Added for TeId %d", teId);
+               }
+               /* As per Spec 38.473, in UE COntext Response, Tunnel information
+                * are sent to CU for setting up of Tunnels in DL direction.
+                * Search for DRB ID in CU databse */
+               for(drbIdx = 0; drbIdx < ueCb->numDrb; drbIdx++)
+               {
+                  if(ueCb->drbList[drbIdx].drbId == drbItemIe->value.choice.DRBs_Setup_Item.dRBID)
+                  {
+                     fillTeIdString(3, teId, ueCb->drbList[drbIdx].dlUpTnlInfo.teId);
+                     break;
+                  }
+               }
             }
             else
                return RFAILED;
@@ -9309,7 +9609,7 @@ uint8_t procUeContextSetupResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
           case ProtocolIE_ID_id_DRBs_Setup_List:
              {
                 /* Adding Tunnels for successful DRB */
-                procDrbSetupList(duId, &ueCtxtSetupRsp->protocolIEs.list.array[idx]->value.choice.DRBs_Setup_List);
+                procDrbSetupList(duId, ueCb, &ueCtxtSetupRsp->protocolIEs.list.array[idx]->value.choice.DRBs_Setup_List);
                 break; 
              }
          case ProtocolIE_ID_id_DUtoCURRCInformation:
@@ -9411,12 +9711,12 @@ uint8_t procUeContextSetupResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
 
 uint8_t procUlRrcMsg(uint32_t duId, F1AP_PDU_t *f1apMsg)
 {
-   uint8_t idx, ret, srbId, rrcMsgType, duIdx=0;
-   uint8_t cuUeF1apId, duUeF1apId;
-   uint8_t *rrcContainer = NULLP;
-   uint16_t rrcContLen;
-   DuDb     *duDb;
-   CuUeCb   *ueCb;
+   uint8_t  idx = 0, ret = ROK, srbId = 0, rrcMsgType = 0, duIdx=0;
+   uint8_t  *rrcContainer = NULLP;
+   uint16_t rrcContLen = 0;
+   uint32_t cuUeF1apId = 0, duUeF1apId = 0;
+   DuDb     *duDb = NULLP;
+   CuUeCb   *ueCb = NULLP;
    ULRRCMessageTransfer_t *ulRrcMsg = NULLP;
 
    ret = ROK;
@@ -9453,8 +9753,32 @@ uint8_t procUlRrcMsg(uint32_t duId, F1AP_PDU_t *f1apMsg)
                memcpy(rrcContainer, ulRrcMsg->protocolIEs.list.array[idx]->value.choice.RRCContainer.buf, rrcContLen);
 
                if(duDb->ueCb[duUeF1apId-1].state == UE_HANDOVER_IN_PROGRESS)
-                  return;
-
+               {
+                  uint8_t ueIdx = 0;
+                  uint8_t srcDuId = duDb->ueCb[duUeF1apId-1].hoInfo.sourceDuId;
+                  DuDb *srcDuDb = NULLP;
+
+                  /* In target DU DB, mark UE as active and delete HO info */
+                  duDb->ueCb[duUeF1apId-1].state = UE_ACTIVE;
+                  memset(&duDb->ueCb[duUeF1apId-1].hoInfo, 0, sizeof(HandoverInfo));
+
+                  /* Release UE context in source DU because the UE is now
+                   * attached to target DU */
+                  SEARCH_DU_DB(duIdx, srcDuId, srcDuDb);
+                  for(ueIdx = 0; ueIdx < srcDuDb->numUe; ueIdx++)
+                  {
+                     if(srcDuDb->ueCb[ueIdx].gnbCuUeF1apId == cuUeF1apId)
+                     {
+                        ret = BuildAndSendUeContextReleaseCommand(srcDuId, srcDuDb->ueCb[ueIdx].gnbCuUeF1apId, srcDuDb->ueCb[ueIdx].gnbDuUeF1apId); 
+                        if(ret != ROK)
+                        {
+                           DU_LOG("\nINFO  -->  F1AP: Failed to build and send UE context release command to source DU Id [%d]", srcDuId);
+                        }
+                        break;
+                     }
+                  }
+                  return ret;
+               }
                break;
             }
 
@@ -9471,10 +9795,15 @@ uint8_t procUlRrcMsg(uint32_t duId, F1AP_PDU_t *f1apMsg)
       rrcMsgType = setDlRRCMsgType(ueCb);
       if(rrcMsgType == RRC_SETUP_COMPLETE)
       {
-         DU_LOG("\nINFO  -->  F1AP: Sending DL RRC MSG for Security Mode Command"); 
+         DU_LOG("\nINFO  -->  F1AP: Sending DL RRC MSG for NAS Security Mode Command");
          ret = BuildAndSendDLRRCMessageTransfer(duId, ueCb, srbId, rrcMsgType);
       }
-      else if(rrcMsgType == SECURITY_MODE_COMPLETE)
+      if(rrcMsgType == NAS_SECURITY_MODE_COMPLETE)
+      {
+         DU_LOG("\nINFO  -->  F1AP: Sending DL RRC MSG for RRC Security Mode Command"); 
+         ret = BuildAndSendDLRRCMessageTransfer(duId, ueCb, srbId, rrcMsgType);
+      }
+      else if(rrcMsgType == RRC_SECURITY_MODE_COMPLETE)
       {
          DU_LOG("\nINFO  -->  F1AP: Sending DL RRC MSG for RRC Registration Accept");
          BuildAndSendDLRRCMessageTransfer(duId, ueCb, srbId, rrcMsgType);
@@ -10609,14 +10938,18 @@ uint8_t BuildAndSendUeContextModificationReq(uint32_t duId, void *cuUeCb, UeCtxt
       ueContextModifyReq =&f1apMsg->choice.initiatingMessage->value.choice.UEContextModificationRequest;
 
       if(action == MODIFY_UE)
-         elementCnt = 4;
+         elementCnt = 5;
       else if(action == QUERY_CONFIG)
          elementCnt = 3;
       else if(action == RRC_RECONFIG_COMPLETE_IND)
          elementCnt = 3;
       else if((action == STOP_DATA_TX) || (action == RESTART_DATA_TX)) 
          elementCnt = 5;
-
+      
+#ifdef NR_DRX
+      if(DRX_TO_BE_RELEASE)
+         elementCnt++;
+#endif      
       ueContextModifyReq->protocolIEs.list.count = elementCnt;
       ueContextModifyReq->protocolIEs.list.size = elementCnt*sizeof(UEContextModificationRequest_t *);
 
@@ -10742,6 +11075,20 @@ uint8_t BuildAndSendUeContextModificationReq(uint32_t duId, void *cuUeCb, UeCtxt
          ueContextModifyReq->protocolIEs.list.array[ieIdx]->value.choice.RRCDeliveryStatusRequest = RRCDeliveryStatusRequest_true;
       }
 
+#ifdef NR_DRX
+      if(DRX_TO_BE_RELEASE)
+      {
+         /* DRX Configuration Indicator */
+         ieIdx++;
+         ueContextModifyReq->protocolIEs.list.array[ieIdx]->id = ProtocolIE_ID_id_DRXConfigurationIndicator;
+         ueContextModifyReq->protocolIEs.list.array[ieIdx]->criticality = Criticality_ignore;
+         ueContextModifyReq->protocolIEs.list.array[ieIdx]->value.present = UEContextModificationRequestIEs__value_PR_DRXConfigurationIndicator;
+         ueContextModifyReq->protocolIEs.list.array[ieIdx]->value.choice.DRXConfigurationIndicator = DRXConfigurationIndicator_release;
+         ueCb->drxCfgPresent = false;
+         memset(&ueCb->drxCfg, 0, sizeof(DrxCfg));
+      }
+#endif
+
       xer_fprint(stdout, &asn_DEF_F1AP_PDU, f1apMsg);
 
       /* Encode the F1SetupRequest type as APER */
@@ -11350,7 +11697,7 @@ uint8_t procServedCellPlmnList(ServedPLMNs_List_t *srvPlmn)
  * ****************************************************************/
 uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
 {
-   uint8_t idx=0, duIdx=0;
+   uint8_t idx=0, duIdx=0, countiX =1;
    uint8_t duUeF1apId = 0, cuUeF1apId = 0;
    DuDb *duDb = NULLP;
    CuUeCb *ueCb = NULLP;
@@ -11436,7 +11783,14 @@ uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
          }
       }
    }
-   
+#ifdef NR_DRX
+   if(countiX == 1)
+   {
+      countiX++;
+      DU_LOG("\nPBORLA INFO  -->  F1AP: Sending UE Context Modification Request to MODIFY_UE");
+      //BuildAndSendUeContextModificationReq(duId, ueCb, MODIFY_UE);
+   }
+#endif
    return ROK;
 }
 
@@ -11480,13 +11834,11 @@ void procF1SetupReq(uint32_t *destDuId, F1AP_PDU_t *f1apMsg)
               if(duDb == NULLP)
               {
                  duDb = &cuCb.duInfo[cuCb.numDu];
-                 memset(duDb, 0, sizeof(DuDb));
-                 duDb->duId = duId;
                  cuCb.numDu++;
-                 *destDuId = duId;
               }
-              else
-                 return;
+              memset(duDb, 0, sizeof(DuDb));
+              duDb->duId = duId;
+              *destDuId = duId;
               break;
            }
          case ProtocolIE_ID_id_gNB_DU_Name:
@@ -11557,7 +11909,7 @@ void procF1SetupReq(uint32_t *destDuId, F1AP_PDU_t *f1apMsg)
 * ****************************************************************/
 void procUeContextReleaseComplete(uint32_t duId, F1AP_PDU_t *f1apMsg)
 {
-   uint8_t duIdx = 0, ieIdx = 0, ueIdx = 0;
+   uint8_t duIdx = 0, ieIdx = 0, ueIdx = 0, drbIdx = 0;
    uint8_t gnbDuUeF1apId = 0, gnbCuUeF1apId = 0;
    DuDb *duDb = NULLP;
    CuUeCb *ueCb = NULLP;
@@ -11591,6 +11943,10 @@ void procUeContextReleaseComplete(uint32_t duId, F1AP_PDU_t *f1apMsg)
                      if((ueCb->cellCb->ueCb[ueIdx]->gnbCuUeF1apId == gnbCuUeF1apId) &&
                            (ueCb->cellCb->ueCb[ueIdx]->gnbDuUeF1apId == gnbDuUeF1apId))
                      {
+                        for(drbIdx = 0; drbIdx < ueCb->numDrb; drbIdx++)
+                        {
+                           deleteEgtpTunnel(duId, ueCb->drbList[drbIdx].dlUpTnlInfo.teId);
+                        }
                         ueCb->cellCb->ueCb[ueIdx] = NULLP;
                         ueCb->cellCb->numUe--;
                         if((ueCb->cellCb->numUe == 0) && (ueCb->cellCb->cellStatus == CELL_DELETION_IN_PROGRESS))