Epic-ID: ODUHIGH-463][Task-ID: ODUHIGH-504]Dummy Handover Request/Response and UE...
[o-du/l2.git] / src / cu_stub / cu_f1ap_msg_hdl.c
index 11607bf..a40b865 100644 (file)
 #include "ProtocolIE-Field.h"
 #include "ProtocolExtensionField.h"
 #include "ProtocolIE-SingleContainer.h"
+#include "F1SetupResponse.h"
+#include "SuccessfulOutcome.h"
+#include "InitiatingMessage.h"
+#include "NonDynamic5QIDescriptor.h"
+#include "AveragingWindow.h"
+#include "MaxDataBurstVolume.h"
+#include "Flows-Mapped-To-DRB-Item.h"
+#include "SliceSupportItem.h"
+#include "ServedPLMNs-Item.h"
 #include "F1AP-PDU.h"
+#include "ULUPTNLInformation-ToBeSetup-Item.h"
+#include "ULConfiguration.h"
 #include "ModulationOrder.h"
 #include "BandNR.h"
 #include "UE-CapabilityRAT-Container.h"
 #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"
@@ -165,7 +177,7 @@ S16 SendF1APMsg(Region region, Pool pool, uint32_t duId)
       {
          ODU_PRINT_MSG(mBuf, 0,0);
 
-         if(sctpSend(duId, mBuf) != ROK)
+         if(sctpSend(F1_INTERFACE, duId, mBuf) != ROK)
          {
             DU_LOG("\nERROR  -->  F1AP : SCTP Send failed");
             ODU_PUT_MSG_BUF(mBuf);
@@ -212,10 +224,10 @@ uint8_t BuildAndSendF1SetupRsp(uint32_t duId, BIT_STRING_t *nrcellId)
    uint8_t    idx,ieIdx;
    uint8_t    elementCnt,cellCnt;
    F1AP_PDU_t         *f1apMsg = NULL;
-   F1SetupResponse_t  *f1SetupRsp;
-   GNB_CU_Name_t      *cuName;
+   F1SetupResponse_t  *f1SetupRsp = NULL;
+   GNB_CU_Name_t      *cuName = NULL;
    Cells_to_be_Activated_List_t *cellToActivate;
-   RRC_Version_t      *rrcVer;
+   RRC_Version_t      *rrcVer = NULL;
    asn_enc_rval_t     encRetVal; 
    DU_LOG("\nINFO  -->  F1AP : Building F1 Setup Response\n");
 
@@ -242,7 +254,7 @@ uint8_t BuildAndSendF1SetupRsp(uint32_t duId, BIT_STRING_t *nrcellId)
                                                       SuccessfulOutcome__value_PR_F1SetupResponse;
    f1SetupRsp = &f1apMsg->choice.successfulOutcome->value.choice.F1SetupResponse;
 
-   elementCnt = 4;
+   elementCnt = 3;
    f1SetupRsp->protocolIEs.list.count = elementCnt;
    f1SetupRsp->protocolIEs.list.size = elementCnt*sizeof(F1SetupResponseIEs_t *);
 
@@ -279,58 +291,54 @@ uint8_t BuildAndSendF1SetupRsp(uint32_t duId, BIT_STRING_t *nrcellId)
                                                             F1SetupResponseIEs__value_PR_TransactionID;
    f1SetupRsp->protocolIEs.list.array[idx]->value.choice.TransactionID =\
                                                                         TRANS_ID;
-
+#if 0
+   /* CU name IE is of type printableString_t which wireshark is unable to decode.
+    * However this string is decoded successfully on online decoders.
+    * Since this is an optional IE and the value received in it are not
+    * used as of now, eliminating this IE for now to avoid wireshark error.
+    */
    /*CU Name*/
    idx++;
    f1SetupRsp->protocolIEs.list.array[idx]->id = ProtocolIE_ID_id_gNB_CU_Name;
    f1SetupRsp->protocolIEs.list.array[idx]->criticality = Criticality_ignore;
-   f1SetupRsp->protocolIEs.list.array[idx]->value.present = \
-                                                            F1SetupResponseIEs__value_PR_GNB_CU_Name;
+   f1SetupRsp->protocolIEs.list.array[idx]->value.present = F1SetupResponseIEs__value_PR_GNB_CU_Name;
    cuName = &f1SetupRsp->protocolIEs.list.array[idx]->value.choice.GNB_CU_Name;
-   cuName->size = sizeof(cuCb.cuCfgParams.cuName);
+   cuName->size = strlen((char *)cuCb.cuCfgParams.cuName);
 
-   CU_ALLOC(cuName->buf, sizeof(cuName->size)); 
+   CU_ALLOC(cuName->buf, cuName->size); 
    if(cuName->buf == NULLP)
    {
       for(ieIdx=0; ieIdx<elementCnt; ieIdx++)
       {
-         CU_FREE(f1SetupRsp->protocolIEs.list.array[ieIdx],\
-               sizeof(F1SetupResponseIEs_t));
+         CU_FREE(f1SetupRsp->protocolIEs.list.array[ieIdx], sizeof(F1SetupResponseIEs_t));
       }
-      CU_FREE(f1SetupRsp->protocolIEs.list.array,\
-            elementCnt * sizeof(F1SetupResponseIEs_t *));
-      CU_FREE(f1apMsg->choice.successfulOutcome,\
-            sizeof(SuccessfulOutcome_t));
+      CU_FREE(f1SetupRsp->protocolIEs.list.array, elementCnt * sizeof(F1SetupResponseIEs_t *));
+      CU_FREE(f1apMsg->choice.successfulOutcome, sizeof(SuccessfulOutcome_t));
       CU_FREE(f1apMsg, sizeof(F1AP_PDU_t));
       return RFAILED;
    }
    strcpy((char*)cuName->buf, (char*)cuCb.cuCfgParams.cuName);
+#endif
 
    /*Cells to be activated list*/
    idx++;
-   f1SetupRsp->protocolIEs.list.array[idx]->id = \
-                                                 ProtocolIE_ID_id_Cells_to_be_Activated_List ;
+   f1SetupRsp->protocolIEs.list.array[idx]->id = ProtocolIE_ID_id_Cells_to_be_Activated_List ;
    f1SetupRsp->protocolIEs.list.array[idx]->criticality = Criticality_reject;
-   f1SetupRsp->protocolIEs.list.array[idx]->value.present = \
-                                                            F1SetupResponseIEs__value_PR_Cells_to_be_Activated_List;
-   cellToActivate = &f1SetupRsp->protocolIEs.list.array[idx]->value.choice.\
-                    Cells_to_be_Activated_List;
+   f1SetupRsp->protocolIEs.list.array[idx]->value.present = F1SetupResponseIEs__value_PR_Cells_to_be_Activated_List;
+   cellToActivate = &f1SetupRsp->protocolIEs.list.array[idx]->value.choice.Cells_to_be_Activated_List;
+
    cellCnt=1;
    cellToActivate->list.count = cellCnt;
-   cellToActivate->list.size = \
-                               cellCnt*sizeof(struct Cells_to_be_Activated_List_ItemIEs  *);
-   CU_ALLOC(cellToActivate->list.array,\
-         sizeof(struct Cells_to_be_Activated_List_ItemIEs  *));
+   cellToActivate->list.size = cellCnt * sizeof(struct Cells_to_be_Activated_List_ItemIEs  *);
+   CU_ALLOC(cellToActivate->list.array, sizeof(struct Cells_to_be_Activated_List_ItemIEs  *));
    if(cellToActivate->list.array == NULLP)
    {
       CU_FREE(cuName->buf, sizeof(cuName->size));
       for(ieIdx=0; ieIdx<elementCnt; ieIdx++)
       {
-         CU_FREE(f1SetupRsp->protocolIEs.list.array[ieIdx],\
-               sizeof(F1SetupResponseIEs_t));
+         CU_FREE(f1SetupRsp->protocolIEs.list.array[ieIdx], sizeof(F1SetupResponseIEs_t));
       }
-      CU_FREE(f1SetupRsp->protocolIEs.list.array,\
-            elementCnt * sizeof(F1SetupResponseIEs_t *));
+      CU_FREE(f1SetupRsp->protocolIEs.list.array, elementCnt * sizeof(F1SetupResponseIEs_t *));
       CU_FREE(f1apMsg->choice.successfulOutcome, sizeof(SuccessfulOutcome_t));
       CU_FREE(f1apMsg, sizeof(F1AP_PDU_t));
       return RFAILED;
@@ -340,18 +348,14 @@ uint8_t BuildAndSendF1SetupRsp(uint32_t duId, BIT_STRING_t *nrcellId)
       CU_ALLOC(cellToActivate->list.array[ieIdx],sizeof(struct Cells_to_be_Activated_List_ItemIEs ));
       if(cellToActivate->list.array[ieIdx] == NULLP)
       {
-         CU_FREE(cellToActivate->list.array,\
-               sizeof(struct Cells_to_be_Activated_List_ItemIEs  *));
+         CU_FREE(cellToActivate->list.array, sizeof(struct Cells_to_be_Activated_List_ItemIEs  *));
          CU_FREE(cuName->buf, sizeof(cuName->size));
          for(ieIdx=0; ieIdx<elementCnt; ieIdx++)
          {
-            CU_FREE(f1SetupRsp->protocolIEs.list.array[ieIdx], \
-                  sizeof(F1SetupResponseIEs_t));
+            CU_FREE(f1SetupRsp->protocolIEs.list.array[ieIdx], sizeof(F1SetupResponseIEs_t));
          }
-         CU_FREE(f1SetupRsp->protocolIEs.list.array, \
-               elementCnt * sizeof(F1SetupResponseIEs_t *));
-         CU_FREE(f1apMsg->choice.successfulOutcome, \
-               sizeof(SuccessfulOutcome_t));
+         CU_FREE(f1SetupRsp->protocolIEs.list.array, elementCnt * sizeof(F1SetupResponseIEs_t *));
+         CU_FREE(f1apMsg->choice.successfulOutcome, sizeof(SuccessfulOutcome_t));
          CU_FREE(f1apMsg, sizeof(F1AP_PDU_t));
          return RFAILED;
       }
@@ -394,10 +398,11 @@ uint8_t BuildAndSendF1SetupRsp(uint32_t duId, BIT_STRING_t *nrcellId)
    buildPlmnId(cuCb.cuCfgParams.plmn , cellToActivate->list.array[0]->value.choice.\
          Cells_to_be_Activated_List_Item.nRCGI.pLMN_Identity.buf);
    cellToActivate->list.array[0]->value.choice.Cells_to_be_Activated_List_Item.\
-      nRCGI.nRCellIdentity.size = 5;
+      nRCGI.nRCellIdentity.size = 5*sizeof(uint8_t);
    CU_ALLOC(cellToActivate->list.array[0]->value.choice.\
          Cells_to_be_Activated_List_Item.nRCGI.nRCellIdentity.buf,\
-         5*sizeof(uint8_t));
+         cellToActivate->list.array[0]->value.choice.Cells_to_be_Activated_List_Item.\
+        nRCGI.nRCellIdentity.size);
    if(cellToActivate->list.array[0]->value.choice.\
          Cells_to_be_Activated_List_Item.nRCGI.nRCellIdentity.buf == NULLP)
    {
@@ -426,6 +431,7 @@ uint8_t BuildAndSendF1SetupRsp(uint32_t duId, BIT_STRING_t *nrcellId)
       return RFAILED;
    }
    memcpy(&cellToActivate->list.array[0]->value.choice.Cells_to_be_Activated_List_Item.nRCGI.nRCellIdentity, nrcellId, sizeof(BIT_STRING_t)); 
+
    /* RRC Version */
    idx++;
    f1SetupRsp->protocolIEs.list.array[idx]->id = \
@@ -560,8 +566,10 @@ uint8_t BuildAndSendF1SetupRsp(uint32_t duId, BIT_STRING_t *nrcellId)
    encRetVal = aper_encode(&asn_DEF_F1AP_PDU, 0, f1apMsg, PrepFinalEncBuf, encBuf);
 
    /* Clean up */
-   CU_FREE(rrcVer->latest_RRC_Version.buf, sizeof(uint8_t));
-   CU_FREE(cuName->buf, sizeof(cuName->size));
+   if(rrcVer)
+      CU_FREE(rrcVer->latest_RRC_Version.buf, sizeof(uint8_t));
+   if(cuName)
+      CU_FREE(cuName->buf, cuName->size);
    for(idx=0; idx<elementCnt; idx++)
    {
       CU_FREE(f1SetupRsp->protocolIEs.list.array[idx], sizeof(F1SetupResponseIEs_t));
@@ -1100,7 +1108,7 @@ uint8_t fillDlCcchRrcMsg(CuUeCb *ueCb, RRCContainer_t *rrcContainer)
                   xer_fprint(stdout, &asn_DEF_DL_CCCH_MessageType, &dl_CCCH_Msg);
                   memset(encBuf, 0, ENC_BUF_MAX_LEN);
                   encBufSize = 0;
-                  encRetVal = aper_encode(&asn_DEF_DL_CCCH_MessageType, 0, &dl_CCCH_Msg, PrepFinalEncBuf, encBuf);
+                  encRetVal = uper_encode(&asn_DEF_DL_CCCH_MessageType, 0, &dl_CCCH_Msg, PrepFinalEncBuf, encBuf);
                   /* Encode results */
                   if(encRetVal.encoded == ENCODE_FAIL)
                   {
@@ -1393,7 +1401,7 @@ uint8_t fillRrcReconfigIE(RRCReconfiguration_IEs_t *rrcReconfigMsg)
  *
  * ****************************************************************/
 
-uint8_t fillDlDcchRrcMsg(CuUeCb *ueCb, RRCContainer_t *rrcContainer)
+uint8_t fillDlDcchRrcMsg(CuUeCb *ueCb, RRCContainer_t *rrcContainer, bool updateAllRbCfg)
 {
    uint8_t ret = ROK;
    uint16_t idx2 = 0, drbIdx = 0, srbIdx = 0;
@@ -1413,7 +1421,7 @@ uint8_t fillDlDcchRrcMsg(CuUeCb *ueCb, RRCContainer_t *rrcContainer)
          if(dl_DCCH_Msg.message.choice.c1->choice.rrcReconfiguration != NULLP)
          {
             DU_LOG("\nDEBUG --> F1AP : Filling DL DCCH RRC Reconfiguration Message ");
-            fillRrcReconfig(ueCb, dl_DCCH_Msg.message.choice.c1->choice.rrcReconfiguration, false);
+            fillRrcReconfig(ueCb, dl_DCCH_Msg.message.choice.c1->choice.rrcReconfiguration, updateAllRbCfg);
             if(ret == ROK)
             {
                /* If RB configuration are filled successfully in RRC Reconfiguration, mark these
@@ -1433,7 +1441,7 @@ uint8_t fillDlDcchRrcMsg(CuUeCb *ueCb, RRCContainer_t *rrcContainer)
                xer_fprint(stdout, &asn_DEF_DL_DCCH_MessageType, &dl_DCCH_Msg);
                memset(encBuf, 0, ENC_BUF_MAX_LEN);
                encBufSize = 0;
-               encRetVal = aper_encode(&asn_DEF_DL_DCCH_MessageType, 0, &dl_DCCH_Msg, PrepFinalEncBuf, encBuf);
+               encRetVal = uper_encode(&asn_DEF_DL_DCCH_MessageType, 0, &dl_DCCH_Msg, PrepFinalEncBuf, encBuf);
                /* Encode results */
                if(encRetVal.encoded == ENCODE_FAIL)
                {
@@ -1510,10 +1518,70 @@ uint8_t BuildDLRRCContainer(CuUeCb *ueCb, uint8_t rrcMsgType, RRCContainer_t *rr
       if(ret == RFAILED)
          DU_LOG("\nERROR  -->  F1AP: Failed to fill DL-CCCH Msg at RRC SETUP");
    }
-   else if(rrcMsgType == REGISTRATION_ACCEPT)
+   else if(rrcMsgType == RRC_SETUP_COMPLETE)
+   {
+      DU_LOG("\nINFO --> F1AP : Sending NAS Authentication Request");
+      char authReqBuf[51] = {0x00, ueCb->pdcpSn++, 0x2a, 0x85, 0x4f, 0xc0, 0x0a, 0xc0, 0x40, 0x40, 0x00, 0x04, 0x2f, 0x58, 0x39, 0x12,\
+                             0x37, 0x15, 0x74, 0x16, 0x4c, 0x8d, 0xd3, 0x95, 0xa6, 0x9e, 0x94, 0x03, 0x24, 0x02, 0x00, 0x6f,\
+                             0x0b, 0x39, 0x5e, 0xbc, 0xb0, 0x00, 0x1a, 0xb1, 0xc1, 0x3f, 0x84, 0x4f, 0x77, 0xe3, 0x20, 0x00,\
+                             0x00, 0x00, 0x00};
+      bufLen = 51;
+      rrcContainer->size = bufLen;
+      CU_ALLOC(rrcContainer->buf, rrcContainer->size);
+      if(rrcContainer->buf != NULLP)
+      {
+         memset(rrcContainer->buf, 0, bufLen); 
+         memcpy(rrcContainer->buf, authReqBuf, bufLen);
+      }
+      else
+      {
+         DU_LOG("\nERROR  -->  F1AP : Memory allocation failure for RRC Container buffer");
+         ret = RFAILED;
+
+      }     
+   }
+   else if(rrcMsgType == NAS_AUTHENTICATION_RSP)
+   {
+      DU_LOG("\nINFO --> F1AP : Sending NAS Security mode command");
+      char secModeBuf[30]={0x00, ueCb->pdcpSn++, 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, ueCb->pdcpSn++, 0x22, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00};
+      bufLen =9;
+      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 == RRC_SECURITY_MODE_COMPLETE)
    {
       /*Hardcoded RRC Container from reference logs*/
-      char buf[14] ={0x00, 0x03, 0x2a, 0x80, 0xaf, 0xc0, 0x08, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00};
+      DU_LOG("\nINFO --> F1AP : Sending Registration accept");
+      char buf[14] ={0x00, ueCb->pdcpSn++, 0x2a, 0x80, 0xaf, 0xc0, 0x08, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00};
       bufLen =14;
       rrcContainer->size = bufLen;
       CU_ALLOC(rrcContainer->buf, rrcContainer->size);
@@ -1528,10 +1596,24 @@ uint8_t BuildDLRRCContainer(CuUeCb *ueCb, uint8_t rrcMsgType, RRCContainer_t *rr
          ret = RFAILED;
       }
    }
-   else if(rrcMsgType == RRC_RECONFIG)
+   else if(rrcMsgType == UE_CONTEXT_SETUP_RSP)
    {
-      DU_LOG("\nDEBUG --> F1AP : Filling DL DCCH RRC Message ");
-      ret = fillDlDcchRrcMsg(ueCb, rrcContainer);
+      uint16_t tmpBufIdx = 0, bufIdx = 0;
+      RRCContainer_t rrcContainerTmp;
+      DU_LOG("\nINFO --> F1AP : Filling DL DCCH RRC Message for RRC Reconfiguration ");
+      ret = fillDlDcchRrcMsg(ueCb, &rrcContainerTmp, false);
+      rrcContainer->size = rrcContainerTmp.size + 2;
+      CU_ALLOC(rrcContainer->buf, rrcContainer->size);
+      if(rrcContainer->buf != NULLP)
+      {
+         memset(rrcContainer->buf, 0, rrcContainer->size);
+         rrcContainer->buf[0] = 0x00;
+         rrcContainer->buf[1] = ueCb->pdcpSn++; //PDCP SN
+         for(bufIdx = 2, tmpBufIdx = 0; bufIdx < rrcContainer->size; bufIdx++, tmpBufIdx++)
+         {
+            rrcContainer->buf[bufIdx] = rrcContainerTmp.buf[tmpBufIdx];
+         }
+      }
       if(ret == RFAILED)
          DU_LOG("\nERROR  -->  F1AP: Failed to fill DL-DCCH Msg for RRC Reconfiguration");
    }
@@ -1744,30 +1826,214 @@ uint8_t setDlRRCMsgType(CuUeCb *ueCb)
       case RRC_SETUP:
          rrcMsgType = RRC_SETUP;
          break;
-      case REGISTRATION_ACCEPT:
-         rrcMsgType = REGISTRATION_ACCEPT;
+      case RRC_SETUP_COMPLETE:
+         rrcMsgType = RRC_SETUP_COMPLETE;
          break;
-      case UE_CONTEXT_SETUP_REQ:
-         rrcMsgType = UE_CONTEXT_SETUP_REQ;
+      case NAS_AUTHENTICATION_RSP:
+         rrcMsgType = NAS_AUTHENTICATION_RSP;
          break;
-      case SECURITY_MODE_COMPLETE:
-         rrcMsgType = SECURITY_MODE_COMPLETE;
+      case NAS_SECURITY_MODE_COMPLETE:
+         rrcMsgType = NAS_SECURITY_MODE_COMPLETE;
          break;
-      case RRC_RECONFIG:
-         rrcMsgType = RRC_RECONFIG;
+      case RRC_SECURITY_MODE_COMPLETE:
+         rrcMsgType = RRC_SECURITY_MODE_COMPLETE;
+         break;
+      case REGISTRATION_COMPLETE:
+         rrcMsgType = REGISTRATION_COMPLETE;
+         break;
+      case UE_CONTEXT_SETUP_RSP:
+         rrcMsgType = UE_CONTEXT_SETUP_RSP;
          break;
       case RRC_RECONFIG_COMPLETE:
          rrcMsgType = RRC_RECONFIG_COMPLETE;
          break;
-      case UE_CONTEXT_MOD_REQ:
-         rrcMsgType = UE_CONTEXT_MOD_REQ;
-         break;
       default:
          break;
    }
    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
@@ -1797,6 +2063,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)
    {
@@ -1810,6 +2079,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;
@@ -1943,11 +2239,11 @@ uint8_t extractDuToCuRrcCont(CuUeCb *ueCb, OCTET_STRING_t rrcCont)
    cellGrpCfgMsg = &cellGrpCfg;
    memset(cellGrpCfgMsg, 0, sizeof(CellGroupConfigRrc_t));
 
-   rval = aper_decode(0, &asn_DEF_CellGroupConfigRrc, (void **)&cellGrpCfgMsg, rrcCont.buf, rrcCont.size, 0, 0);
+   rval = uper_decode(0, &asn_DEF_CellGroupConfigRrc, (void **)&cellGrpCfgMsg, rrcCont.buf, rrcCont.size, 0, 0);
 
    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");
@@ -2270,9 +2566,9 @@ uint8_t BuildQOSInfo(QosInfo *qosInfo, QoSFlowLevelQoSParameters_t *drbQos, uint
       return RFAILED;
    }
    
-   if(hoInProgress)
+   if(hoInProgress == Inter_DU_HO)
       drbQos->qoS_Characteristics.choice.non_Dynamic_5QI->fiveQI = qosInfo->nonDynFiveQI ;
-   else
+   else if(hoInProgress == false || hoInProgress == Xn_Based_Inter_CU_HO)
    {
       /*FiveQI*/
       if(actionType == ProtocolIE_ID_id_DRBs_ToBeModified_Item)
@@ -2311,7 +2607,7 @@ uint8_t BuildQOSInfo(QosInfo *qosInfo, QoSFlowLevelQoSParameters_t *drbQos, uint
       drbQos->nGRANallocationRetentionPriority.pre_emptionCapability = qosInfo->preemptionCapability;
       drbQos->nGRANallocationRetentionPriority.pre_emptionVulnerability = qosInfo->preemptionVulnerability;
    }
-   else
+   else if((hoInProgress == false) || (hoInProgress == Xn_Based_Inter_CU_HO))
    {
       drbQos->nGRANallocationRetentionPriority.priorityLevel = PriorityLevel_lowest;
       drbQos->nGRANallocationRetentionPriority.pre_emptionCapability = Pre_emptionCapability_may_trigger_pre_emption;
@@ -2397,6 +2693,12 @@ uint8_t BuildQOSInfo(QosInfo *qosInfo, QoSFlowLevelQoSParameters_t *drbQos, uint
 uint8_t BuildSNSSAI(DrbInfo *drbInfo, SNSSAI_t *snssai, Snssai *snssaiToCopy, bool hoInProgress)
 {
    /*SNSSAI*/
+   /* In case of non-HO UE context creation and Xn Based HO, DRB's SNSSAI
+    * configuration is not known beforehand. In these 2 case, the following
+    * condition will hit */
+   if(!hoInProgress || (hoInProgress == Xn_Based_Inter_CU_HO))
+      drbInfo->snssai = snssaiToCopy;
+
    /*ssT*/
    snssai->sST.size = sizeof(uint8_t);
    CU_ALLOC(snssai->sST.buf, snssai->sST.size);
@@ -2404,10 +2706,7 @@ uint8_t BuildSNSSAI(DrbInfo *drbInfo, SNSSAI_t *snssai, Snssai *snssaiToCopy, bo
    {
       return RFAILED;
    }
-   if(!hoInProgress)
-      memcpy(snssai->sST.buf, &snssaiToCopy->sst, snssai->sST.size);
-   else
-      memcpy(snssai->sST.buf, &drbInfo->snssai->sst, snssai->sST.size);
+   memcpy(snssai->sST.buf, &drbInfo->snssai->sst, snssai->sST.size);
 
    /*sD*/
    CU_ALLOC(snssai->sD, sizeof(OCTET_STRING_t));
@@ -2421,13 +2720,8 @@ uint8_t BuildSNSSAI(DrbInfo *drbInfo, SNSSAI_t *snssai, Snssai *snssaiToCopy, bo
    {
       return RFAILED;
    }
-   if(!hoInProgress)
-      memcpy(snssai->sD->buf, snssaiToCopy->sd, snssai->sD->size);
-   else
-      memcpy(snssai->sD->buf, drbInfo->snssai->sd, snssai->sD->size);
+   memcpy(snssai->sD->buf, drbInfo->snssai->sd, snssai->sD->size);
 
-   if(!hoInProgress)
-      drbInfo->snssai = snssaiToCopy;
    return ROK;
 }/*End of BuildSNSSAI*/
 
@@ -2452,10 +2746,14 @@ uint8_t BuildFlowsMap(DrbInfo *drbInfo, Flows_Mapped_To_DRB_List_t *flowMap , ui
    uint8_t  ret = ROK, idx = 0, flowCnt = 0, flowIdx = 0;
    FlowsMapped *qosFlow;
 
-   if(!hoInProgress)
+   /* In case of non-HO UE context creation and Xn Based HO, DRB's SNSSAI
+    * configuration is not known beforehand. In these 2 case, the following
+    * condition will hit */
+   if(!hoInProgress || (hoInProgress == Xn_Based_Inter_CU_HO))
       flowCnt = 1;
    else
       flowCnt = drbInfo->numFlowMap;
+
    flowMap->list.count = flowCnt;
    flowMap->list.size = flowCnt * sizeof(Flows_Mapped_To_DRB_Item_t *);
    CU_ALLOC(flowMap->list.array,flowMap->list.size);
@@ -2473,7 +2771,7 @@ uint8_t BuildFlowsMap(DrbInfo *drbInfo, Flows_Mapped_To_DRB_List_t *flowMap , ui
          return RFAILED;
       }
       
-      if(!hoInProgress)
+      if(!hoInProgress || (hoInProgress == Xn_Based_Inter_CU_HO))
       {
          flowMap->list.array[idx]->qoSFlowIdentifier = 0;
          if(actionType == ProtocolIE_ID_id_DRBs_ToBeModified_Item)
@@ -2507,7 +2805,7 @@ uint8_t BuildFlowsMap(DrbInfo *drbInfo, Flows_Mapped_To_DRB_List_t *flowMap , ui
          return RFAILED;
       }
 
-      if((!hoInProgress) && (actionType != ProtocolIE_ID_id_DRBs_ToBeModified_Item))
+      if(((!hoInProgress) && (actionType != ProtocolIE_ID_id_DRBs_ToBeModified_Item)) || (hoInProgress == Xn_Based_Inter_CU_HO))
          drbInfo->numFlowMap++;
    }
    return ROK;
@@ -2570,7 +2868,7 @@ uint8_t BuildULTnlInfo(uint8_t duId, TnlInfo *ulUpTnlInfo, ULUPTNLInformation_To
       return RFAILED;
    }
 
-   if(!hoInProgress)
+   if((!hoInProgress) || (hoInProgress == Xn_Based_Inter_CU_HO))
    {
       /* NOTE: Below IP address must be changed if running on different IP configuration */
       ulInfo->list.array[idx]->uLUPTNLInformation.choice.gTPTunnel->transportLayerAddress.buf[0] = 192;
@@ -2603,7 +2901,7 @@ uint8_t BuildULTnlInfo(uint8_t duId, TnlInfo *ulUpTnlInfo, ULUPTNLInformation_To
       return RFAILED;
    }
    
-   if(!hoInProgress)
+   if((!hoInProgress) || (hoInProgress == Xn_Based_Inter_CU_HO))
    {
       ulInfo->list.array[idx]->uLUPTNLInformation.choice.gTPTunnel->gTP_TEID.buf[0] = 0;
       ulInfo->list.array[idx]->uLUPTNLInformation.choice.gTPTunnel->gTP_TEID.buf[1] = 0;
@@ -2643,6 +2941,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;
@@ -2703,7 +3002,7 @@ uint8_t BuildDRBSetup(uint32_t duId, CuUeCb *ueCb, DRBs_ToBeSetup_List_t *drbSet
                choice_extension->value.choice.DRB_Information.dRB_QoS, ProtocolIE_ID_id_DRBs_ToBeSetup_Item, PDU_SESSION_ID_1, FALSE);
       else
          BuildQOSInforet =  BuildQOSInfo(&ueCb->drbList[idx].qos, &drbSetItem->qoSInformation.choice.\
-               choice_extension->value.choice.DRB_Information.dRB_QoS, ProtocolIE_ID_id_DRBs_ToBeSetup_Item, PDU_SESSION_ID_1, TRUE);
+               choice_extension->value.choice.DRB_Information.dRB_QoS, ProtocolIE_ID_id_DRBs_ToBeSetup_Item, PDU_SESSION_ID_1, ueCb->hoInfo.HOType);
       if(BuildQOSInforet != ROK)
       {
          DU_LOG("\nERROR  -->  F1AP : Failed to build QOS Info in BuildDRBSetup");
@@ -2711,12 +3010,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, cuCb.snssaiList[snssaiIdx], ueCb->hoInfo.HOType);
       if(BuildSNSSAIret != ROK)
       {
          DU_LOG("\nERROR  -->  F1AP : Failed to build SNSSAI Info in BuildDRBSetup");
@@ -2729,7 +3029,7 @@ uint8_t BuildDRBSetup(uint32_t duId, CuUeCb *ueCb, DRBs_ToBeSetup_List_t *drbSet
                value.choice.DRB_Information.flows_Mapped_To_DRB_List, ProtocolIE_ID_id_DRBs_ToBeSetup_Item, FALSE);
       else
          BuildFlowsMapret = BuildFlowsMap(&ueCb->drbList[idx], &drbSetItem->qoSInformation.choice.choice_extension->\
-               value.choice.DRB_Information.flows_Mapped_To_DRB_List, ProtocolIE_ID_id_DRBs_ToBeSetup_Item, TRUE);
+               value.choice.DRB_Information.flows_Mapped_To_DRB_List, ProtocolIE_ID_id_DRBs_ToBeSetup_Item, ueCb->hoInfo.HOType);
       if(BuildFlowsMapret != ROK)
       {
          DU_LOG("\nERROR  -->  F1AP : Failed to build Flow Map Info in BuildDRBSetup");
@@ -2742,7 +3042,7 @@ uint8_t BuildDRBSetup(uint32_t duId, CuUeCb *ueCb, DRBs_ToBeSetup_List_t *drbSet
                FALSE);
       else
          BuildULTnlInforet = BuildULTnlInfo(duId, &ueCb->drbList[idx].ulUpTnlInfo, &drbSetItem->uLUPTNLInformation_ToBeSetup_List,\
-               TRUE);
+               ueCb->hoInfo.HOType);
       if(BuildULTnlInforet != ROK)
       {
          DU_LOG("\nERROR  -->  F1AP : Failed to build tunnel Info in BuildDRBSetup");
@@ -2750,7 +3050,7 @@ uint8_t BuildDRBSetup(uint32_t duId, CuUeCb *ueCb, DRBs_ToBeSetup_List_t *drbSet
       }
 
       /*RLCMode*/
-      if(ueCb->state != UE_HANDOVER_IN_PROGRESS)
+      if((ueCb->state != UE_HANDOVER_IN_PROGRESS) || (ueCb->hoInfo.HOType == Xn_Based_Inter_CU_HO))
       {
          drbSetItem->rLCMode = RLCMode_rlc_um_bidirectional;
          ueCb->drbList[ueCb->numDrb].rlcMode = drbSetItem->rLCMode;
@@ -5251,7 +5551,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)
@@ -6474,7 +6774,7 @@ uint8_t fillCellGrpCfg(CuUeCb *ueCb, OCTET_STRING_t *cellGrp, bool updateAllRbCf
       xer_fprint(stdout, &asn_DEF_CellGroupConfigRrc, &cellGrpCfg);
       cmMemset((uint8_t *)encBuf, 0, ENC_BUF_MAX_LEN);
       encBufSize = 0;
-      encRetVal = aper_encode(&asn_DEF_CellGroupConfigRrc, 0, &cellGrpCfg, PrepFinalEncBuf, encBuf);
+      encRetVal = uper_encode(&asn_DEF_CellGroupConfigRrc, 0, &cellGrpCfg, PrepFinalEncBuf, encBuf);
       /* Encode results */
       if(encRetVal.encoded == ENCODE_FAIL)
       {
@@ -6862,7 +7162,7 @@ uint8_t fillUeCapRatCont(OCTET_STRING_t *ueCapRatContBuf)
       xer_fprint(stdout, &asn_DEF_UE_NR_Capability, &ueNrCap);
       cmMemset((uint8_t *)encBuf, 0, ENC_BUF_MAX_LEN);
       encBufSize = 0;
-      encRetVal = aper_encode(&asn_DEF_UE_NR_Capability, 0, &ueNrCap, PrepFinalEncBuf, encBuf);
+      encRetVal = uper_encode(&asn_DEF_UE_NR_Capability, 0, &ueNrCap, PrepFinalEncBuf, encBuf);
    
       /* Encode results */
       if(encRetVal.encoded == ENCODE_FAIL)
@@ -6990,7 +7290,7 @@ uint8_t fillUeCapRatContListBuf(UE_CapabilityRAT_ContainerList_t *ueCapablityLis
       xer_fprint(stdout, &asn_DEF_UE_CapabilityRAT_ContainerListRRC, &ueCapablityList);
       cmMemset((uint8_t *)encBuf, 0, ENC_BUF_MAX_LEN);
       encBufSize = 0;
-      encRetVal = aper_encode(&asn_DEF_UE_CapabilityRAT_ContainerListRRC, 0, \
+      encRetVal = uper_encode(&asn_DEF_UE_CapabilityRAT_ContainerListRRC, 0, \
             &ueCapablityList, PrepFinalEncBuf, encBuf);
 
       /* Encode results */
@@ -7188,7 +7488,7 @@ uint8_t fillMeasTimingConfigBuf(MeasConfig_t *measTimingConfigBuf)
       xer_fprint(stdout, &asn_DEF_MeasurementTimingConfigurationRrc, &measTimingConfig);
       cmMemset((uint8_t *)encBuf, 0, ENC_BUF_MAX_LEN);
       encBufSize = 0;
-      encRetVal = aper_encode(&asn_DEF_MeasurementTimingConfigurationRrc, 0, &measTimingConfig, PrepFinalEncBuf, encBuf);
+      encRetVal = uper_encode(&asn_DEF_MeasurementTimingConfigurationRrc, 0, &measTimingConfig, PrepFinalEncBuf, encBuf);
 
       /* Encode results */
       if(encRetVal.encoded == ENCODE_FAIL)
@@ -7535,7 +7835,7 @@ void freeSrbToAddModList(SRB_ToAddModList_t *srbToAddList)
  *
  * @details
  *
- *    Function : fillRadioBearerConfig
+ *    Function : freeRadioBearerConfig 
  *
  *    Functionality: Free Radio Bearer config
  *
@@ -7631,12 +7931,6 @@ uint8_t fillSrbToAddModList(CuUeCb *ueCb, SRB_ToAddModList_t *srbToAddList, bool
       return ROK;
    }
 
-   CU_ALLOC(srbToAddList, sizeof(SRB_ToAddModList_t));
-   if(!srbToAddList)
-   {
-      DU_LOG("\nERROR  -->  F1AP: Memory allocation failed for SRB to AddMod List in fillRadioBearerConfig");
-      return RFAILED;
-   }
    srbToAddList->list.count = elementCnt;
    srbToAddList->list.size = srbToAddList->list.count * sizeof(SRB_ToAddMod_t *);
 
@@ -7730,13 +8024,6 @@ uint8_t fillDrbToAddModList(CuUeCb *ueCb, DRB_ToAddModList_t *drbToAddList, bool
       return ROK;
    }
    
-   /* DRB To Add/Mod List */
-   CU_ALLOC(drbToAddList, sizeof(DRB_ToAddModList_t));
-   if(!drbToAddList)
-   {
-      DU_LOG("\nERROR  -->  F1AP: Memory allocation failed for DRB to AddMod List in fillRadioBearerConfig");
-      return RFAILED;
-   }
 
    drbToAddList->list.count = elementCnt;
    drbToAddList->list.size = drbToAddList->list.count * sizeof(DRB_ToAddMod_t *);
@@ -7845,13 +8132,28 @@ uint8_t fillDrbToAddModList(CuUeCb *ueCb, DRB_ToAddModList_t *drbToAddList, bool
 uint8_t fillRadioBearerConfig(CuUeCb *ueCb, RadioBearerConfig_t *radioBearerConfig, bool updateAllRbCfg)
 {
    /* SRB To Add/Mod List */
+   CU_ALLOC(radioBearerConfig->srb_ToAddModList, sizeof(SRB_ToAddModList_t));
+   if(!radioBearerConfig->srb_ToAddModList)
+   {
+      DU_LOG("\nERROR  -->  F1AP: Memory allocation failed for SRB to AddMod List in fillRadioBearerConfig");
+      return RFAILED;
+   }
    if(fillSrbToAddModList(ueCb, radioBearerConfig->srb_ToAddModList, updateAllRbCfg) != ROK)
    {
+      DU_LOG("\nERROR  -->  F1AP: failed to fill SRB to AddMod List");
       return RFAILED;
    }
 
+   /* DRB To Add/Mod List */
+   CU_ALLOC(radioBearerConfig->drb_ToAddModList, sizeof(DRB_ToAddModList_t));
+   if(!radioBearerConfig->drb_ToAddModList)
+   {
+      DU_LOG("\nERROR  -->  F1AP: Memory allocation failed for DRB to AddMod List in fillRadioBearerConfig");
+      return RFAILED;
+    }
    if(fillDrbToAddModList(ueCb, radioBearerConfig->drb_ToAddModList, updateAllRbCfg) != ROK)
    {
+      DU_LOG("\nERROR  -->  F1AP: failed to fill DRB to AddMod List ");
       return RFAILED;
    }
 
@@ -7999,7 +8301,7 @@ uint8_t fillMeasObjToAddModList(MeasObjectToAddModList_t *measObjList)
 
    /* RSRQ offset for SSB */
    CU_ALLOC(measObject->offsetMO.rsrqOffsetSSB, sizeof(Q_OffsetRange_t));
-   if(!measObject->offsetMO.rsrpOffsetSSB)
+   if(!measObject->offsetMO.rsrqOffsetSSB)
    {
       DU_LOG("\nERROR  -->  F1AP: Memory allocation failed for SSB RSRQ offset in fillMeasObjToAddModList");
       return RFAILED;
@@ -8554,7 +8856,7 @@ uint8_t fillRrcReconfigBuf(CuUeCb *ueCb, OCTET_STRING_t  *rrcReconfigBuf, bool u
       xer_fprint(stdout, &asn_DEF_RRCReconfiguration, rrcReconfig);
       cmMemset((uint8_t *)encBuf, 0, ENC_BUF_MAX_LEN);
       encBufSize = 0;
-      encRetVal = aper_encode(&asn_DEF_RRCReconfiguration, 0, rrcReconfig, PrepFinalEncBuf, encBuf);
+      encRetVal = uper_encode(&asn_DEF_RRCReconfiguration, 0, rrcReconfig, PrepFinalEncBuf, encBuf);
 
       /* Encode results */
       if(encRetVal.encoded == ENCODE_FAIL)
@@ -8665,7 +8967,7 @@ uint8_t fillHOPreparationInfoBuf(CuUeCb *ueCb, HandoverPreparationInformation_t
       xer_fprint(stdout, &asn_DEF_HandoverPreparationInformationRrc, &hoPrepInfo);
       cmMemset((uint8_t *)encBuf, 0, ENC_BUF_MAX_LEN);
       encBufSize = 0;
-      encRetVal = aper_encode(&asn_DEF_HandoverPreparationInformationRrc, 0, \
+      encRetVal = uper_encode(&asn_DEF_HandoverPreparationInformationRrc, 0, \
             &hoPrepInfo, PrepFinalEncBuf, encBuf);
 
       /* Encode results */
@@ -8720,7 +9022,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));
@@ -8731,6 +9033,21 @@ uint8_t fillCuToDuContainer(CuUeCb *ueCb, CUtoDURRCInformation_t *rrcMsg)
    }
    ret = fillUeCapRatContListBuf(rrcMsg->uE_CapabilityRAT_ContainerList);
 
+#if 0
+
+   /* Commenting this because:
+    * CUToDURRCInformation->MeasConfig contains measurement gap configurations.
+    * Howeever measurement gap is not supported in our code. Measurement Gap will
+    * be required if we want to support inter-RAT handover or handover to
+    * neighbouring cells operating on a different frequency than serving cell.
+    *
+    * In case we plan to use this IE in future, following fixes are required:
+    * As of now, we are filling MeasurementTimingConfigurationRrc_t into rrcMsg->measConfig.
+    * This is incorrect. We must fill MeasConfigRrc_t in rrcMsg->measConfig.
+    * MeasurementTimingConfigurationRrc_t should be filled in 
+    * rrcMsg->iE_Extensions->MeasurementTimingConfiguration, if required.
+    */
+
    CU_ALLOC(rrcMsg->measConfig, sizeof(MeasConfig_t));
    if(!rrcMsg->measConfig)
    {
@@ -8738,6 +9055,7 @@ uint8_t fillCuToDuContainer(CuUeCb *ueCb, CUtoDURRCInformation_t *rrcMsg)
       return RFAILED;
    }
    ret = fillMeasTimingConfigBuf(rrcMsg->measConfig);
+#endif
 
    if(ueCb->state == UE_HANDOVER_IN_PROGRESS)
    {
@@ -8788,39 +9106,74 @@ uint8_t fillCuToDuContainer(CuUeCb *ueCb, CUtoDURRCInformation_t *rrcMsg)
    }
    return ret;
 }
-
 /*******************************************************************
  *
- * @brief Free CuToDuContainer 
+ * @brief Build the drx cycle  
  *
  * @details
  *
- *    Function : FreeCuToDuInfo
+ *    Function : BuildDrxCycle
  *
- *    Functionality: Free CuToDuContainer
+ *    Functionality: Build drx cycle IE
  *
- * @params[in] pointer to CUtoDURRCInformation_t
+ * @params[in] pointer to DRXCycle_t
  *
  * @return ROK     - success
  *         RFAILED - failure
  *
  ******************************************************************/
-
-void FreeCuToDuInfo(CUtoDURRCInformation_t *rrcMsg)
+uint8_t BuildDrxCycle(DRXCycle_t *drxCycle)
 {
-   uint8_t idx, idx2;
-
-   if(rrcMsg->uE_CapabilityRAT_ContainerList)
+   drxCycle->longDRXCycleLength = LongDRXCycleLength_ms80;
+   CU_ALLOC(drxCycle->shortDRXCycleLength, sizeof(ShortDRXCycleLength_t));
+   if(!drxCycle->shortDRXCycleLength)
    {
-      if(rrcMsg->uE_CapabilityRAT_ContainerList->buf)
-         CU_FREE(rrcMsg->uE_CapabilityRAT_ContainerList->buf, rrcMsg->uE_CapabilityRAT_ContainerList->size);      
-      CU_FREE(rrcMsg->uE_CapabilityRAT_ContainerList, sizeof(UE_CapabilityRAT_ContainerList_t));
+      DU_LOG("\nERROR  -->  F1AP : Memory allocation failed for shortDRXCycleLength");
+      return RFAILED;
    }
-   if(rrcMsg->iE_Extensions)
+   *(drxCycle->shortDRXCycleLength) = ShortDRXCycleLength_ms4;
+   
+   CU_ALLOC(drxCycle->shortDRXCycleTimer, sizeof(ShortDRXCycleTimer_t));
+   if(!drxCycle->shortDRXCycleTimer)
    {
-      if(rrcMsg->iE_Extensions->list.array)
-      {
-        for(idx= 0; idx < rrcMsg->iE_Extensions->list.count; idx++)
+      DU_LOG("\nERROR  -->  F1AP : Memory allocation failed for shortDRXCycleTimer");
+      return RFAILED;
+   }
+   *(drxCycle->shortDRXCycleTimer) = 4;
+   return ROK;
+}
+/*******************************************************************
+ *
+ * @brief Free CuToDuContainer 
+ *
+ * @details
+ *
+ *    Function : FreeCuToDuInfo
+ *
+ *    Functionality: Free CuToDuContainer
+ *
+ * @params[in] pointer to CUtoDURRCInformation_t
+ *
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ ******************************************************************/
+
+void FreeCuToDuInfo(CUtoDURRCInformation_t *rrcMsg)
+{
+   uint8_t idx, idx2;
+
+   if(rrcMsg->uE_CapabilityRAT_ContainerList)
+   {
+      if(rrcMsg->uE_CapabilityRAT_ContainerList->buf)
+         CU_FREE(rrcMsg->uE_CapabilityRAT_ContainerList->buf, rrcMsg->uE_CapabilityRAT_ContainerList->size);      
+      CU_FREE(rrcMsg->uE_CapabilityRAT_ContainerList, sizeof(UE_CapabilityRAT_ContainerList_t));
+   }
+   if(rrcMsg->iE_Extensions)
+   {
+      if(rrcMsg->iE_Extensions->list.array)
+      {
+        for(idx= 0; idx < rrcMsg->iE_Extensions->list.count; idx++)
         {
            if(rrcMsg->iE_Extensions->list.array[idx])
            {
@@ -8870,13 +9223,14 @@ void FreeCuToDuInfo(CUtoDURRCInformation_t *rrcMsg)
  *         RFAILED - failure
  *
  * ****************************************************************/
-uint8_t BuildAndSendUeContextSetupReq(uint32_t duId, CuUeCb *ueCb, uint16_t rrcContLen, uint8_t *rrcContainer)
+uint8_t BuildAndSendUeContextSetupReq(uint32_t duId, CuUeCb *ueCb)
 {
    uint8_t   Nrcgiret, SplCellListret, SrbSetupret;
    uint8_t   ret= RFAILED, ret1;
    uint8_t   elementCnt;
    uint8_t   idx, idx1, bufLen, duIdx;
    uint32_t  spCellId;
+   uint32_t  targetDuId;
    DuDb      *targetDuDb = NULLP;
    F1AP_PDU_t          *f1apMsg = NULLP;
    UEContextSetupRequest_t *ueSetReq = NULLP;
@@ -8911,7 +9265,13 @@ uint8_t BuildAndSendUeContextSetupReq(uint32_t duId, CuUeCb *ueCb, uint16_t rrcC
       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 *);
 
@@ -8956,16 +9316,23 @@ uint8_t BuildAndSendUeContextSetupReq(uint32_t duId, CuUeCb *ueCb, uint16_t rrcC
       ueSetReq->protocolIEs.list.array[idx]->id        = ProtocolIE_ID_id_SpCell_ID;
       ueSetReq->protocolIEs.list.array[idx]->criticality       =       Criticality_reject;
       ueSetReq->protocolIEs.list.array[idx]->value.present = UEContextSetupRequestIEs__value_PR_NRCGI;
+
+      /* Spec 38.473 Sec 9.2.2.1 : For handover case, this IE shall be considered as target cell. */
       if(ueCb->state == UE_HANDOVER_IN_PROGRESS)
       {
-         /* Spec 38.473 Sec 9.2.2.1 : For handover case, this IE shall be considered as target cell. */
-         SEARCH_DU_DB(duIdx, ueCb->hoInfo.targetDuId, targetDuDb);
+         if(ueCb->hoInfo.HOType == Inter_DU_HO)
+            targetDuId = ueCb->hoInfo.tgtNodeId;
+         else
+            targetDuId = duId;
+
+         SEARCH_DU_DB(duIdx, targetDuId, targetDuDb);
          /* Since we are supporting only one cell per DU, accessing 0th index to
           * get target cell info */
          spCellId = targetDuDb->cellCb[0].nrCellId;
       }
       else
          spCellId = ueCb->cellCb->nrCellId;
+
       Nrcgiret = BuildNrcgi(&ueSetReq->protocolIEs.list.array[idx]->value.choice.NRCGI, spCellId);
       if(Nrcgiret != ROK)
       {
@@ -9001,6 +9368,18 @@ uint8_t BuildAndSendUeContextSetupReq(uint32_t duId, CuUeCb *ueCb, uint16_t rrcC
 
       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;
@@ -9037,25 +9416,6 @@ uint8_t BuildAndSendUeContextSetupReq(uint32_t duId, CuUeCb *ueCb, uint16_t rrcC
 
       if(ueCb->state != UE_HANDOVER_IN_PROGRESS)
       {
-         /* RRC Container for security mode */
-         idx++;
-         ueSetReq->protocolIEs.list.array[idx]->id = ProtocolIE_ID_id_RRCContainer;
-         ueSetReq->protocolIEs.list.array[idx]->criticality = Criticality_reject;
-         ueSetReq->protocolIEs.list.array[idx]->value.present = UEContextSetupRequestIEs__value_PR_RRCContainer;
-
-         char secModeBuf[9]={0x00, 0x02, 0x22, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00};
-         bufLen =9;
-         ueSetReq->protocolIEs.list.array[idx]->value.choice.RRCContainer.size = bufLen;
-         CU_ALLOC(ueSetReq->protocolIEs.list.array[idx]->value.choice.RRCContainer.buf,
-               ueSetReq->protocolIEs.list.array[idx]->value.choice.RRCContainer.size);
-         if(!ueSetReq->protocolIEs.list.array[idx]->value.choice.RRCContainer.buf)
-         {
-            DU_LOG("\nERROR  -->  F1AP : Memory allocation for BuildAndSendUeContextSetupReq failed");
-            break;
-         }
-         memset(ueSetReq->protocolIEs.list.array[idx]->value.choice.RRCContainer.buf, 0, bufLen);
-         memcpy(ueSetReq->protocolIEs.list.array[idx]->value.choice.RRCContainer.buf, secModeBuf, bufLen);
-
          /* RRC delivery status request */
          idx++;
          ueSetReq->protocolIEs.list.array[idx]->id = ProtocolIE_ID_id_RRCDeliveryStatusRequest;
@@ -9212,9 +9572,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 +9589,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;
@@ -9257,9 +9628,9 @@ uint8_t procDrbSetupList(uint32_t duId, DRBs_Setup_List_t *drbSetupList)
  *         RFAILED - failure
  *
  * ****************************************************************/
-uint8_t procUeContextSetupResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
+uint8_t procUeContextSetupResponse(uint32_t duId, F1AP_PDU_t *f1apMsg, char *recvBuf, MsgLen recvBufLen)
 {
-   uint8_t duIdx = 0, idx = 0, ueIdx = 0;
+   uint8_t duIdx = 0, idx = 0, ueIdx = 0, rrcMsgType=0;
    uint8_t duUeF1apId = 0, cuUeF1apId = 0;
    DuDb *duDb = NULLP;
    CuUeCb *ueCb = NULLP;
@@ -9289,11 +9660,24 @@ uint8_t procUeContextSetupResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
                 {
                    /* Creating UE context in target DU */
                    memset(ueCb, 0, sizeof(CuUeCb));
-                   ueCb->cellCb = &duDb->cellCb[0];
-                   ueCb->gnbDuUeF1apId = duUeF1apId;
-                   ueCb->gnbCuUeF1apId = cuUeF1apId;
-                   ueCb->state = UE_HANDOVER_IN_PROGRESS;
-                   ueCb->hoInfo.targetDuId = duId; 
+
+                   /* Check if UE is under Inter-CU handover */
+                   if(duDb->tempUeCtxtInHo && (duDb->tempUeCtxtInHo->gnbCuUeF1apId == cuUeF1apId))
+                   {
+                      memcpy(ueCb, duDb->tempUeCtxtInHo, sizeof(CuUeCb));
+                      ueCb->gnbDuUeF1apId = duUeF1apId;
+                      CU_FREE(duDb->tempUeCtxtInHo, sizeof(CuUeCb));
+                   }
+                   else
+                   {
+                      /* In case of Inter DU Handover */
+                      ueCb->cellCb = &duDb->cellCb[0];
+                      ueCb->gnbDuUeF1apId = duUeF1apId;
+                      ueCb->gnbCuUeF1apId = cuUeF1apId;
+                      ueCb->state = UE_HANDOVER_IN_PROGRESS;
+                      ueCb->hoInfo.HOType = Inter_DU_HO;
+                      ueCb->hoInfo.tgtNodeId = duId; 
+                   }
                    (duDb->numUe)++;
 
                    ueCb->cellCb->ueCb[ueCb->cellCb->numUe] = ueCb;
@@ -9309,7 +9693,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:
@@ -9327,58 +9711,77 @@ uint8_t procUeContextSetupResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
              }
       }
    }
-
-   ueCb->f1apMsgDb.dlRrcMsgCount++; /* keeping DL RRC Msg Count */
-
-   /* If the UE is in handover, UE context modification request is to be sent to
-    * source DU once UE context setup response is received from target DU */
-   if(ueCb->state == UE_HANDOVER_IN_PROGRESS)
+   
+   if(ueCb->state != UE_HANDOVER_IN_PROGRESS)
    {
-      DuDb *srcDuDb = NULLP;
-      CuUeCb *ueCbInSrcDu = NULLP;
+      ueCb->f1apMsgDb.dlRrcMsgCount++;
+      rrcMsgType = setDlRRCMsgType(ueCb);
 
-      /* Since Source DU Id and DU UE F1AP ID assigned to UE by source DU is not known here, we
-       * need to find Source DU and UE CB in source DU using CU UE F1AP ID */
-      for(duIdx=0; duIdx < cuCb.numDu; duIdx++)
+      DU_LOG("\nINFO  -->  F1AP: Sending DL RRC MSG for RRC reconfiguration");
+      if(BuildAndSendDLRRCMessageTransfer(duId, ueCb, SRB1, rrcMsgType) != ROK)
+      {     
+         DU_LOG("\nINFO  -->  F1AP: Failed to build and send DL RRC MSG for RRC reconfiguration");
+         return RFAILED;
+      }     
+   }
+   else if(ueCb->state == UE_HANDOVER_IN_PROGRESS)
+   {
+      if(ueCb->hoInfo.HOType == Inter_DU_HO)
       {
-         /* UE context setup response is received from target DU. Search all
-          * DUs to find source DU except this target DU Id.*/
-         if(cuCb.duInfo[duIdx].duId != duId)
+         /* If the UE is in Inter-DU handover, UE context modification request is to be sent to
+          * source DU once UE context setup response is received from target DU */
+
+         DuDb *srcDuDb = NULLP;
+         CuUeCb *ueCbInSrcDu = NULLP;
+
+         /* Since Source DU Id and DU UE F1AP ID assigned to UE by source DU is not known here, we
+          * need to find Source DU and UE CB in source DU using CU UE F1AP ID */
+         for(duIdx=0; duIdx < cuCb.numDu; duIdx++)
          {
-            for(ueIdx = 0; ueIdx < MAX_NUM_UE; ueIdx++)
+            /* UE context setup response is received from target DU. Search all
+             * DUs to find source DU except this target DU Id.*/
+            if(cuCb.duInfo[duIdx].duId != duId)
             {
-               /* Check following:
-                * 1. CU UE F1AP ID in srcDU->ueCb should be same as cuUeF1apId
-                * received in UE context setup response since CU UE F1AP ID does not
-                * change for UE in handover.
-                * 2. srcDU->UeCb->uestate should be UE_HANDOVER_IN_PROGRESS
-                */
-               if((cuCb.duInfo[duIdx].ueCb[ueIdx].gnbCuUeF1apId == cuUeF1apId) &&
-                     (cuCb.duInfo[duIdx].ueCb[ueIdx].state == UE_HANDOVER_IN_PROGRESS))
+               for(ueIdx = 0; ueIdx < MAX_NUM_UE; ueIdx++)
                {
-                  srcDuDb = &cuCb.duInfo[duIdx];
-                  ueCbInSrcDu = &cuCb.duInfo[duIdx].ueCb[ueIdx];
+                  /* Check following:
+                   * 1. CU UE F1AP ID in srcDU->ueCb should be same as cuUeF1apId
+                   * received in UE context setup response since CU UE F1AP ID does not
+                   * change for UE in handover.
+                   * 2. srcDU->UeCb->uestate should be UE_HANDOVER_IN_PROGRESS
+                   */
+                  if((cuCb.duInfo[duIdx].ueCb[ueIdx].gnbCuUeF1apId == cuUeF1apId) &&
+                        (cuCb.duInfo[duIdx].ueCb[ueIdx].state == UE_HANDOVER_IN_PROGRESS))
+                  {
+                     srcDuDb = &cuCb.duInfo[duIdx];
+                     ueCbInSrcDu = &cuCb.duInfo[duIdx].ueCb[ueIdx];
 
-                  /* Store source DU info in the new UE context created in
-                   * tareget DU */
-                  ueCb->hoInfo.sourceDuId = srcDuDb->duId;
+                     /* Store source DU info in the new UE context created in
+                      * tareget DU */
+                     ueCb->hoInfo.srcNodeId = srcDuDb->duId;
 
-                  /* Copy the received container to UeCb */
-                  memcpy(&ueCbInSrcDu->f1apMsgDb.duToCuContainer, duToCuRrcContainer, sizeof(OCTET_STRING_t));
+                     /* Copy the received container to UeCb */
+                     memcpy(&ueCbInSrcDu->f1apMsgDb.duToCuContainer, duToCuRrcContainer, sizeof(OCTET_STRING_t));
 
-                  if(BuildAndSendUeContextModificationReq(srcDuDb->duId, ueCbInSrcDu, STOP_DATA_TX) != ROK)
-                  {
-                     DU_LOG("\nERROR  ->  F1AP : Failed at BuildAndSendUeContextModificationReq()");
-                     return RFAILED;
+                     if(BuildAndSendUeContextModificationReq(srcDuDb->duId, ueCbInSrcDu, STOP_DATA_TX) != ROK)
+                     {
+                        DU_LOG("\nERROR  ->  F1AP : Failed at BuildAndSendUeContextModificationReq()");
+                        return RFAILED;
+                     }
+                     break;
                   }
-                  break;
                }
             }
+            if(srcDuDb && ueCbInSrcDu)
+               break;
          }
-         if(srcDuDb && ueCbInSrcDu)
-            break;
+      }
+      else if(ueCb->hoInfo.HOType == Xn_Based_Inter_CU_HO)
+      {
+         BuildAndSendHOReqAck(ueCb, recvBuf, recvBufLen);
       }
    }
+
    return ROK;
 }
 
@@ -9400,12 +9803,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;
@@ -9442,8 +9845,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.srcNodeId;
+                  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;
             }
 
@@ -9458,37 +9885,20 @@ uint8_t procUlRrcMsg(uint32_t duId, F1AP_PDU_t *f1apMsg)
       ueCb = &duDb->ueCb[duUeF1apId-1];
       ueCb->f1apMsgDb.dlRrcMsgCount++;
       rrcMsgType = setDlRRCMsgType(ueCb);
-      if(rrcMsgType == REGISTRATION_ACCEPT)
+      if(rrcMsgType == REGISTRATION_COMPLETE)
       {
-         DU_LOG("\nINFO  -->  F1AP: Sending DL RRC MSG for RRC Registration Accept"); 
-         ret = BuildAndSendDLRRCMessageTransfer(duId, ueCb, srbId, rrcMsgType);
+         DU_LOG("\nINFO  -->  F1AP: Sending Ue Context Setup Request"); 
+         ret = BuildAndSendUeContextSetupReq(duId, ueCb);
       }
-      if(rrcMsgType == UE_CONTEXT_SETUP_REQ)
+      else if(rrcMsgType == RRC_RECONFIG_COMPLETE)
       {
-         DU_LOG("\nINFO  -->  F1AP: Sending Ue Context Setup Req"); 
-         ret = BuildAndSendUeContextSetupReq(duId, ueCb, rrcContLen, rrcContainer);
+         DU_LOG("\nINFO  -->  F1AP: Sending UE Context Modification Request");
+         BuildAndSendUeContextModificationReq(duId, ueCb, RRC_RECONFIG_COMPLETE_IND);
       }
-      if(rrcMsgType == SECURITY_MODE_COMPLETE)
+      else
       {
-         /* To trigger the DL RRC Msg for RRC Reconfig */
-         ueCb->f1apMsgDb.dlRrcMsgCount++;
-         rrcMsgType = setDlRRCMsgType(ueCb);
-         if(rrcMsgType == RRC_RECONFIG)
-         {
-            DU_LOG("\nINFO  -->  F1AP: Sending DL RRC MSG for RRC Reconfig");
-            BuildAndSendDLRRCMessageTransfer(duId, ueCb, srbId, rrcMsgType);
-         }
-      }
-      if(rrcMsgType == RRC_RECONFIG_COMPLETE)
-      {
-         ueCb->state = UE_ACTIVE;
-         ueCb->f1apMsgDb.dlRrcMsgCount++;
-         rrcMsgType = setDlRRCMsgType(ueCb);
-         if(rrcMsgType == UE_CONTEXT_MOD_REQ)
-         {
-            DU_LOG("\nINFO  -->  F1AP: Sending UE Context Modification Request");
-            BuildAndSendUeContextModificationReq(duId, ueCb, RRC_RECONFIG_COMPLETE_IND);
-         }
+         /* In case rrcMsgType is RRC_SETUP_COMPLETE / NAS_AUTHENTICATION_RSP / NAS_SECURITY_MODE_COMPLETE / RRC_SECURITY_MODE_COMPLETE */
+         BuildAndSendDLRRCMessageTransfer(duId, ueCb, srbId, rrcMsgType);
       }
    }
    return ret;
@@ -10368,6 +10778,95 @@ uint8_t BuildDrbToBeModifiedList(uint32_t duId, CuUeCb *ueCb, DRBs_ToBeModified_
    return ret;
 }
 
+/*******************************************************************
+*
+* @brief Builds the DRB to be released Item IE
+*
+* @details
+*
+*    Function : FillDrbToBeRelItemList
+*
+*    Functionality: Constructs the DRB to be modified Mod Item Ies
+*
+* @params[in] struct DRBs_ToBeReleased_ItemIEs *drbItemIe
+*
+* @return ROK     - success
+*         RFAILED - failure
+*
+* ****************************************************************/
+
+uint8_t FillDrbToBeRelItemList(uint32_t duId, CuUeCb *ueCb, uint8_t arrIdx, struct DRBs_ToBeReleased_ItemIEs *drbItemIe)
+{
+   uint8_t drbIdx;
+
+   drbItemIe->id = ProtocolIE_ID_id_DRBs_ToBeReleased_Item;
+   drbItemIe->criticality = Criticality_reject;
+   drbItemIe->value.present = DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item;
+   drbItemIe->value.choice.DRBs_ToBeReleased_Item.dRBID = DRB1 + arrIdx;
+
+   for(drbIdx = 0; drbIdx < ueCb->numDrb; drbIdx++)
+   {
+      if(ueCb->drbList[drbIdx].drbId == drbItemIe->value.choice.DRBs_ToBeReleased_Item.dRBID)
+      {
+         deleteEgtpTunnel(duId, ueCb->drbList[drbIdx].dlUpTnlInfo.teId);
+         CU_FREE(ueCb->drbList[drbIdx].snssai, sizeof(Snssai));
+         break;
+      }
+   }
+   return ROK;
+}
+
+/*******************************************************************
+*
+* @brief Builds the DRB to be released list 
+*
+* @details
+*
+*    Function : BuildDrbToBeReleasedList 
+*
+*    Functionality: Constructs the DRB to be released list
+*
+* @params[in] DRBs_ToBeReleased_List_t *drbSet 
+*
+* @return ROK     - success
+*         RFAILED - failure
+*
+* ****************************************************************/
+
+uint8_t BuildDrbToBeReleasedList(uint32_t duId, CuUeCb *ueCb, DRBs_ToBeReleased_List_t *drbSet)
+{
+   uint8_t ret = ROK;
+   uint8_t arrIdx =0;
+   uint8_t drbCnt =0;
+
+   drbCnt = MAX_DRB_MODIFIED_UE_MOD_REQ;
+   drbSet->list.count = drbCnt;
+   drbSet->list.size = drbCnt * sizeof(DRBs_ToBeReleased_ItemIEs_t *);
+   CU_ALLOC(drbSet->list.array, drbSet->list.size);
+   if(drbSet->list.array == NULLP)
+   {
+      DU_LOG("\nERROR  -->  F1AP : Memory allocation failed in BuildDrbToBeReleasedList");
+      return  RFAILED;
+   }
+   for(arrIdx=0; arrIdx<drbCnt; arrIdx++)
+   {
+      CU_ALLOC(drbSet->list.array[arrIdx], sizeof(DRBs_ToBeReleased_ItemIEs_t));
+      if(drbSet->list.array[arrIdx] == NULLP)
+      {
+         DU_LOG("\nERROR  -->  F1AP : Memory allocation failed in BuildDrbToBeReleasedList");
+         return  RFAILED;
+      }
+
+      ret = FillDrbToBeRelItemList(duId, ueCb, arrIdx, (DRBs_ToBeReleased_ItemIEs_t *)drbSet->list.array[arrIdx]);
+      if(ret != ROK)
+      {
+         DU_LOG("\nERROR  -->  F1AP : FillDrbToBeRelItemList failed");
+      }
+   }
+
+   return ret;
+}
+
 /*******************************************************************
 *
 * @brief freeing the DRB  item
@@ -10489,6 +10988,40 @@ void FreeDrbToBeModifiedList(DRBs_ToBeModified_List_t *drbSet)
 
 }
 
+/*******************************************************************
+*
+* @brief free the DRB to be modfified list
+*
+* @details
+*
+*    Function : FreeDrbToBeReleasedList
+*
+*    Functionality: free the DRB to be Release list
+*
+* @params[in] FreeDrbToBeReleasedList_t *drbSet
+*
+* @return ROK     - success
+*         RFAILED - failure
+*
+* ****************************************************************/
+void FreeDrbToBeReleasedList(DRBs_ToBeReleased_List_t *drbSet)
+{
+   uint8_t arrIdx =0;
+   struct DRBs_ToBeReleased_ItemIEs *drbItemIe;
+
+   if(drbSet->list.array)
+   {
+      for(arrIdx=0; arrIdx<drbSet->list.count ; arrIdx++)
+      {
+         if(drbSet->list.array[arrIdx] != NULLP)
+         {
+            CU_FREE(drbSet->list.array[arrIdx], sizeof(DRBs_ToBeReleased_ItemIEs_t));
+         }
+      }
+      CU_FREE(drbSet->list.array, drbSet->list.size);
+   }
+}
+
 /*******************************************************************
  *
  * @brief  free the UeContextModification Request 
@@ -10540,6 +11073,12 @@ void FreeUeContextModicationRequest(F1AP_PDU_t *f1apMsg)
                                  choice.DRBs_ToBeModified_List);
                            break;
                         }
+                     case ProtocolIE_ID_id_DRBs_ToBeReleased_List:
+                        {
+                           FreeDrbToBeReleasedList(&ueContextModifyReq->protocolIEs.list.array[arrIdx]->value.\
+                                 choice.DRBs_ToBeReleased_List);
+                           break;
+                        }
                     case ProtocolIE_ID_id_TransmissionActionIndicator:
                         break;
                     case ProtocolIE_ID_id_RRCContainer:
@@ -10581,9 +11120,11 @@ uint8_t BuildAndSendUeContextModificationReq(uint32_t duId, void *cuUeCb, UeCtxt
    uint8_t    ieIdx = 0;
    uint8_t    elementCnt = 0;
    uint8_t    ret = RFAILED;
+   uint16_t   tmpBufIdx = 0, bufIdx = 0;
    CuUeCb     *ueCb = (CuUeCb *)cuUeCb;
    F1AP_PDU_t *f1apMsg = NULLP;
    UEContextModificationRequest_t *ueContextModifyReq = NULLP;
+   RRCContainer_t rrcContainerTmp, *rrcContainer = NULLP;
    asn_enc_rval_t         encRetVal;
    DU_LOG("\nINFO  -->  F1AP : Building Ue context modification request\n");
    while(1)
@@ -10610,14 +11151,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 && ueCb->drxCfgPresent)
+         elementCnt++;
+#endif      
       ueContextModifyReq->protocolIEs.list.count = elementCnt;
       ueContextModifyReq->protocolIEs.list.size = elementCnt*sizeof(UEContextModificationRequest_t *);
 
@@ -10673,15 +11218,26 @@ uint8_t BuildAndSendUeContextModificationReq(uint32_t duId, void *cuUeCb, UeCtxt
          ret = BuildDrbToBeModifiedList(duId, ueCb, &(ueContextModifyReq->protocolIEs.list.array[ieIdx]->\
                   value.choice.DRBs_ToBeModified_List));
 
-         /* TODO: DRB to be release list */
-
          if(ret != ROK)
          {
             DU_LOG("\nERROR  -->  F1AP : BuildAndSendUeContextModificationReq(): Failed to build drb to be modified list");
             break;
          }
 
-         /* TODO: fill the RRC reconfiguration information in RRC Contaiiner ie in case of MODIFY_UE  */
+         /* DRB to be released list */
+         ieIdx++;
+         ueContextModifyReq->protocolIEs.list.array[ieIdx]->id = ProtocolIE_ID_id_DRBs_ToBeReleased_List;
+         ueContextModifyReq->protocolIEs.list.array[ieIdx]->criticality = Criticality_reject;
+         ueContextModifyReq->protocolIEs.list.array[ieIdx]->value.present =\
+                                                                 UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List;
+         ret = BuildDrbToBeReleasedList(duId, ueCb, &(ueContextModifyReq->protocolIEs.list.array[ieIdx]->\
+                  value.choice.DRBs_ToBeReleased_List));
+
+         if(ret != ROK)
+         {
+            DU_LOG("\nERROR  -->  F1AP : BuildAndSendUeContextModificationReq(): Failed to build drb to be deleted list");
+            break;
+         }
       }
       else if(action == QUERY_CONFIG)
       {
@@ -10727,14 +11283,24 @@ uint8_t BuildAndSendUeContextModificationReq(uint32_t duId, void *cuUeCb, UeCtxt
          ieIdx++;
          ueContextModifyReq->protocolIEs.list.array[ieIdx]->id = ProtocolIE_ID_id_RRCContainer;
          ueContextModifyReq->protocolIEs.list.array[ieIdx]->criticality = Criticality_reject;
-         ueContextModifyReq->protocolIEs.list.array[ieIdx]->value.present = \
-         UEContextModificationRequestIEs__value_PR_RRCContainer;
-         if(fillRrcReconfigBuf(ueCb, &ueContextModifyReq->protocolIEs.list.array[ieIdx]->value.choice.RRCContainer, true) != ROK)
+         ueContextModifyReq->protocolIEs.list.array[ieIdx]->value.present = UEContextModificationRequestIEs__value_PR_RRCContainer;
+         if(fillDlDcchRrcMsg(ueCb, &rrcContainerTmp, true) != ROK)
          {
             DU_LOG( "\nERROR  -->  F1AP : Failed to fill Rrc reconfiguration buffer");
             return RFAILED;
          }
 
+         rrcContainer = &ueContextModifyReq->protocolIEs.list.array[ieIdx]->value.choice.RRCContainer;
+         rrcContainer->size = rrcContainerTmp.size + 2; /* 2 bytes of PDCP SN */
+         CU_ALLOC(rrcContainer->buf, rrcContainer->size);
+         memset(rrcContainer->buf, 0, rrcContainer->size);
+         rrcContainer->buf[0] = 0x00;
+         rrcContainer->buf[1] = ueCb->pdcpSn; //PDCP SN
+         for(bufIdx = 2, tmpBufIdx = 0; bufIdx < rrcContainer->size; bufIdx++, tmpBufIdx++)
+         {
+            rrcContainer->buf[bufIdx] = rrcContainerTmp.buf[tmpBufIdx];
+         }
+
          /* RRC delivery status request */
          ieIdx++;
          ueContextModifyReq->protocolIEs.list.array[ieIdx]->id = ProtocolIE_ID_id_RRCDeliveryStatusRequest;
@@ -10743,6 +11309,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 && ueCb->drxCfgPresent)
+      {
+         /* 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 */
@@ -11257,17 +11837,17 @@ uint8_t procDrbSetupModList(uint32_t duId, CuUeCb *ueCb, DRBs_SetupMod_List_t *d
 
             if(ueCb->state != UE_HANDOVER_IN_PROGRESS)
             {
-            /* extracting teId */
-            teId  = extractTeId(&drbItemIe->value.choice.DRBs_SetupMod_Item.dLUPTNLInformation_ToBeSetup_List);
-            if(teId > 0)
-            {
-              if(addDrbTunnels(duId, teId)== ROK)
-              {
-                DU_LOG("\nDEBUG  --> EGTP: Tunnel Added for TeId %d", teId);
-              }
-            }
-            else
-               return RFAILED;
+               /* extracting teId */
+               teId  = extractTeId(&drbItemIe->value.choice.DRBs_SetupMod_Item.dLUPTNLInformation_ToBeSetup_List);
+               if(teId > 0)
+               {
+                  if(addDrbTunnels(duId, teId)== ROK)
+                  {
+                     DU_LOG("\nDEBUG  --> EGTP: Tunnel Added for TeId %d", teId);
+                  }
+               }
+               else
+                  return RFAILED;
             }
          }
       }
@@ -11349,7 +11929,7 @@ uint8_t procServedCellPlmnList(ServedPLMNs_List_t *srvPlmn)
  *         RFAILED - failure
  *
  * ****************************************************************/
-uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
+uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg, char *recvBuf, MsgLen recvBufLen)
 {
    uint8_t idx=0, duIdx=0;
    uint8_t duUeF1apId = 0, cuUeF1apId = 0;
@@ -11359,6 +11939,10 @@ uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
 
    SEARCH_DU_DB(duIdx, duId, duDb);
    ueCtxtModRsp = &f1apMsg->choice.successfulOutcome->value.choice.UEContextModificationResponse;
+
+   /* In case of Inter-CU Handover request received from peer CU */
+   if(duDb->tempUeCtxtInHo)
+      ueCb = duDb->tempUeCtxtInHo;
    
    for(idx=0; idx < ueCtxtModRsp->protocolIEs.list.count; idx++)
    {
@@ -11366,13 +11950,29 @@ uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
       {
           case ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
              {
-                cuUeF1apId = ueCtxtModRsp->protocolIEs.list.array[idx]->value.choice.GNB_CU_UE_F1AP_ID;
+                if(ueCb == NULLP)
+                {
+                   cuUeF1apId = ueCtxtModRsp->protocolIEs.list.array[idx]->value.choice.GNB_CU_UE_F1AP_ID;
+                }
+                else
+                {
+                   /* In case of Inter-CU Handover request received from peer CU */
+                   cuUeF1apId = ueCb->gnbCuUeF1apId;
+                }
                 break;
              }
           case ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
              {
-                duUeF1apId = ueCtxtModRsp->protocolIEs.list.array[idx]->value.choice.GNB_DU_UE_F1AP_ID;
-                ueCb = &duDb->ueCb[duUeF1apId-1];
+                if(!ueCb)
+                {
+                   duUeF1apId = ueCtxtModRsp->protocolIEs.list.array[idx]->value.choice.GNB_DU_UE_F1AP_ID;
+                   ueCb = &duDb->ueCb[duUeF1apId-1];
+
+                   if((ueCb->state == UE_HANDOVER_IN_PROGRESS) && (ueCb->hoInfo.HOType == Xn_Based_Inter_CU_HO))
+                   {
+                      BuildAndSendHOReq(ueCb, recvBuf, recvBufLen);
+                   }
+                }
                 break;
              }
           case ProtocolIE_ID_id_DRBs_SetupMod_List:
@@ -11382,6 +11982,11 @@ uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
                 break; 
 
              }
+             case ProtocolIE_ID_id_DRBs_Modified_List:
+             {
+                DU_LOG("\nINFO  -->  Received DRBs Modified List");
+                break;
+             }
           case ProtocolIE_ID_id_SRBs_SetupMod_List:
              {
                 procSrbSetupModList(ueCb, &ueCtxtModRsp->protocolIEs.list.array[idx]->value.choice.SRBs_SetupMod_List);
@@ -11407,10 +12012,20 @@ uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
    if(ueCb->state == UE_HANDOVER_IN_PROGRESS)
    {
       uint8_t ueIdx = 0;
+      uint8_t tgtDuId = 0;
       DuDb *tgtDuDb = NULLP;
       CuUeCb *ueCbInTgtDu = NULLP;
 
-      SEARCH_DU_DB(duIdx, ueCb->hoInfo.targetDuId, tgtDuDb);
+      if(ueCb->hoInfo.HOType == Inter_DU_HO)
+      {
+         tgtDuId = ueCb->hoInfo.tgtNodeId;
+      }
+      else if (ueCb->hoInfo.HOType == Xn_Based_Inter_CU_HO)
+      {
+         tgtDuId =  duId;
+      }
+
+      SEARCH_DU_DB(duIdx, tgtDuId, tgtDuDb);
       if(tgtDuDb)
       {
          /* Since DU UE F1AP ID assigned by target DU to this UE in handover is
@@ -11425,11 +12040,11 @@ uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
             }
          }
 
-         /* If UE context is not found in Target DU DU, send UE context setup
+         /* If UE context is not found in Target DU, send UE context setup
           * request */
          if(ueCbInTgtDu == NULLP)
          {
-            if((BuildAndSendUeContextSetupReq(ueCb->hoInfo.targetDuId, ueCb, 0, NULLP)) != ROK)
+            if((BuildAndSendUeContextSetupReq(tgtDuId, ueCb)) != ROK)
             {
                DU_LOG("\nERROR  ->  F1AP : Failed at BuildAndSendUeContextSetupReq");
                return RFAILED;
@@ -11437,7 +12052,11 @@ uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
          }
       }
    }
-   
+
+#ifdef START_DL_UL_DATA
+   startDlData();
+#endif
+
    return ROK;
 }
 
@@ -11460,7 +12079,8 @@ uint8_t procUeContextModificationResponse(uint32_t duId, F1AP_PDU_t *f1apMsg)
 void procF1SetupReq(uint32_t *destDuId, F1AP_PDU_t *f1apMsg)
 {
    uint8_t ieIdx = 0, plmnidx=0, duIdx = 0, ret=ROK, cellIdx = 0;
-   uint32_t duId = 0, nrCellId = 0;
+   uint32_t duId = 0;
+   uint64_t nrCellId = 0;
    DuDb     *duDb = NULLP;
    CuCellCb *cellCb = NULLP;
    BIT_STRING_t nrcellIdentity;
@@ -11468,6 +12088,10 @@ void procF1SetupReq(uint32_t *destDuId, F1AP_PDU_t *f1apMsg)
    GNB_DU_Served_Cells_Item_t *srvCellItem = NULLP; 
    GNB_DU_Served_Cells_List_t *duServedCell = NULLP;
 
+   /* Triggering XN setup request before F1 setup establishment */
+   if(LOCAL_NODE_TYPE == CLIENT)
+      BuildAndSendXnSetupReq();
+
    f1SetupReq = &f1apMsg->choice.initiatingMessage->value.choice.F1SetupRequest;
    for(ieIdx=0; ieIdx < f1SetupReq->protocolIEs.list.count; ieIdx++)
    {
@@ -11480,13 +12104,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:
@@ -11511,8 +12133,7 @@ void procF1SetupReq(uint32_t *destDuId, F1AP_PDU_t *f1apMsg)
                               ret = procServedCellPlmnList(&srvCellItem->served_Cell_Information.servedPLMNs);
                               memcpy(&nrcellIdentity, &srvCellItem->served_Cell_Information.nRCGI.nRCellIdentity, sizeof(BIT_STRING_t));
                               
-                              /* TODO : Use bitStringToInt */
-                              nrCellId = nrcellIdentity.buf[4] >> nrcellIdentity.bits_unused;
+                              bitStringToInt(&nrcellIdentity, &nrCellId);
                               SEARCH_CELL_DB(cellIdx, duDb, nrCellId, cellCb);
                               if(cellCb == NULLP)
                               {
@@ -11558,7 +12179,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;
@@ -11592,9 +12213,13 @@ 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))
+                        if((ueCb->cellCb->numUe == 0) && (ueCb->cellCb->cellStatus == CELL_DELETION_IN_PROGRESS))
                         {
                            memset(ueCb->cellCb, 0, sizeof(CuCellCb));
                            duDb->numCells--;
@@ -11802,6 +12427,11 @@ uint8_t BuildAndSendPagingMsg(uint64_t gsTmsi, uint8_t duId)
       DU_LOG("\nERROR  -->  F1AP : BuildAndSendPagingMsg(): DuDb is empty");
       return ret; 
    }
+   if(duDb->numCells == 0)
+   {
+      DU_LOG("\nERROR  -->  F1AP : BuildAndSendPagingMsg(): No CELL is UP!");
+      return ret; 
+   }
 
    while(true)
    {
@@ -11969,7 +12599,7 @@ uint8_t BuildAndSendPagingMsg(uint64_t gsTmsi, uint8_t duId)
 
 /*******************************************************************
  *
- * @brief Handles received F1AP message and sends back response  
+ * @brief Decode received character string into F1AP message 
  *
  * @details
  *
@@ -11977,61 +12607,86 @@ uint8_t BuildAndSendPagingMsg(uint64_t gsTmsi, uint8_t duId)
  *
  *    Functionality:
  *         - Decodes received F1AP control message
- *         - Prepares response message, encodes and sends to SCTP
  *
  * @params[in] 
  * @return ROK     - success
  *         RFAILED - failure
  *
  * ****************************************************************/
-void F1APMsgHdlr(uint32_t *duId, Buffer *mBuf)
+uint8_t F1APDecodeMsg(F1AP_PDU_t *f1apMsg, Buffer *mBuf, char **recvBuf, MsgLen *recvBufLen)
 {
    int i;
-   char *recvBuf;
    MsgLen copyCnt;
-   MsgLen recvBufLen;
-   F1AP_PDU_t *f1apMsg = NULLP;
    asn_dec_rval_t rval; /* Decoder return value */
-   F1AP_PDU_t f1apasnmsg ;
-
-   DU_LOG("\nINFO  -->  F1AP : Received F1AP message buffer");
-   ODU_PRINT_MSG(mBuf, 0,0);
 
    /* Copy mBuf into char array to decode it */
-   ODU_GET_MSG_LEN(mBuf, &recvBufLen);
-   CU_ALLOC(recvBuf, (Size)recvBufLen);
-
-   if(recvBuf == NULLP)
+   ODU_GET_MSG_LEN(mBuf, recvBufLen);
+   CU_ALLOC(*recvBuf, (Size)(*recvBufLen));
+   if(*recvBuf == NULLP)
    {
       DU_LOG("\nERROR  -->  F1AP : Memory allocation failed");
-      return;
+      return RFAILED;
    }
-   if(ODU_COPY_MSG_TO_FIX_BUF(mBuf, 0, recvBufLen, (Data *)recvBuf, &copyCnt) != ROK)
+   if(ODU_COPY_MSG_TO_FIX_BUF(mBuf, 0, *recvBufLen, (Data *)*recvBuf, &copyCnt) != ROK)
    {
       DU_LOG("\nERROR  -->  F1AP : Failed while copying %d", copyCnt);
-      return;
+      return RFAILED;
    }
 
-   DU_LOG("\nDEBUG  -->  F1AP : Received flat buffer to be decoded : ");
-   for(i=0; i< recvBufLen; i++)
+   DU_LOG("\nDEBUG  -->  F1AP : Received flat buffer to be decoded : \n");
+   for(i=0; i< *recvBufLen; i++)
    {
-      DU_LOG("%x",recvBuf[i]);
+      DU_LOG("%x ",(*recvBuf)[i]);
    }
 
    /* Decoding flat buffer into F1AP messsage */
-   f1apMsg = &f1apasnmsg;
-   memset(f1apMsg, 0, sizeof(F1AP_PDU_t));
-
-   rval = aper_decode(0, &asn_DEF_F1AP_PDU, (void **)&f1apMsg, recvBuf, recvBufLen, 0, 0);
-   CU_FREE(recvBuf, (Size)recvBufLen);
-
+   rval = aper_decode(0, &asn_DEF_F1AP_PDU, (void **)&f1apMsg, *recvBuf, *recvBufLen, 0, 0);
    if(rval.code == RC_FAIL || rval.code == RC_WMORE)
    {
       DU_LOG("\nERROR  -->  F1AP : ASN decode failed");
-      return;
+      return RFAILED;
    }
+
+   /* Printing the decoded F1AP PDU */
    DU_LOG("\n");
    xer_fprint(stdout, &asn_DEF_F1AP_PDU, f1apMsg);
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Handles received F1AP message and sends back response  
+ *
+ * @details
+ *
+ *    Function : F1APMsgHdlr
+ *
+ *    Functionality:
+ *         - Decodes received F1AP control message
+ *         - Prepares response message, encodes and sends to SCTP
+ *
+ * @params[in] 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+void F1APMsgHdlr(uint32_t *duId, Buffer *mBuf)
+{
+   char *recvBuf;
+   MsgLen recvBufLen;
+   F1AP_PDU_t *f1apMsg = NULLP;
+   F1AP_PDU_t f1apasnmsg ;
+
+   DU_LOG("\nINFO  -->  F1AP : Received F1AP message buffer");
+   ODU_PRINT_MSG(mBuf, 0,0);
+
+   f1apMsg = &f1apasnmsg;
+   memset(f1apMsg, 0, sizeof(F1AP_PDU_t));
+   if(F1APDecodeMsg(f1apMsg, mBuf, &recvBuf, &recvBufLen) != ROK)
+   {
+      DU_LOG("\nERROR  -->  F1AP : F1AP PDU decode failed");
+      return;
+   }
 
    switch(f1apMsg->present)
    {
@@ -12105,13 +12760,13 @@ void F1APMsgHdlr(uint32_t *duId, Buffer *mBuf)
                case SuccessfulOutcome__value_PR_UEContextSetupResponse:
                   {
                      DU_LOG("\nINFO  -->  F1AP : UE ContextSetupResponse received");
-                     procUeContextSetupResponse(*duId, f1apMsg);
+                     procUeContextSetupResponse(*duId, f1apMsg, recvBuf, recvBufLen);
                      break;
                   }
                case SuccessfulOutcome__value_PR_UEContextModificationResponse:
                   {
                      DU_LOG("\nINFO  -->  F1AP : UE Context Modification Response received");
-                     procUeContextModificationResponse(*duId, f1apMsg);
+                     procUeContextModificationResponse(*duId, f1apMsg, recvBuf, recvBufLen);
                      break;
                   }
                case SuccessfulOutcome__value_PR_UEContextReleaseComplete:
@@ -12136,6 +12791,7 @@ void F1APMsgHdlr(uint32_t *duId, Buffer *mBuf)
          }
    }/* End of switch(f1apMsg->present) */
 
+   CU_FREE(recvBuf, (Size)(recvBufLen));
 } /* End of F1APMsgHdlr */
 
 /**********************************************************************