diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c
index cc29a92ebb21251daec16b18066b7e54d5d6e0aa..6fe48ed611cfdc3a3342f1a06beef44a6787c550 100644
--- a/openair2/F1AP/f1ap_cu_ue_context_management.c
+++ b/openair2/F1AP/f1ap_cu_ue_context_management.c
@@ -38,31 +38,153 @@
 
 #include "rrc_extern.h"
 #include "openair2/RRC/NR/rrc_gNB_NGAP.h"
-#include <openair3/ocp-gtpu/gtp_itf.h>
-#include "LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
 
-static void setQos(F1AP_NonDynamic5QIDescriptor_t **toFill)
+static void f1ap_write_drb_qos_param(const f1ap_qos_flow_level_qos_parameters_t *drb_qos_in, F1AP_QoSFlowLevelQoSParameters_t *asn1_qosparam)
 {
-  asn1cCalloc(*toFill, tmp);
-  /* fiveQI */
-  tmp->fiveQI = 1L;
+  int type = drb_qos_in->qos_characteristics.qos_type;
+
+  const f1ap_qos_characteristics_t *drb_qos_char_in = &drb_qos_in->qos_characteristics;
+  if (type == non_dynamic) {
+    asn1_qosparam->qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
+    asn1cCalloc(asn1_qosparam->qoS_Characteristics.choice.non_Dynamic_5QI, tmp);
+
+    /* 5QI */
+    tmp->fiveQI = drb_qos_char_in->non_dynamic.fiveqi;
+  } else {
+    asn1_qosparam->qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
+    asn1cCalloc(asn1_qosparam->qoS_Characteristics.choice.dynamic_5QI, tmp);
+    /* qoSPriorityLevel */
+    tmp->qoSPriorityLevel = drb_qos_char_in->dynamic.qos_priority_level;
+    /* packetDelayBudget */
+    tmp->packetDelayBudget = drb_qos_char_in->dynamic.packet_delay_budget;
+    /* packetErrorRate */
+    tmp->packetErrorRate.pER_Scalar = drb_qos_char_in->dynamic.packet_error_rate.per_scalar;
+    tmp->packetErrorRate.pER_Exponent = drb_qos_char_in->dynamic.packet_error_rate.per_scalar;
+
+    /* OPTIONAL delayCritical */
+    // asn1cCallocOne(asn1_qosparam->qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L);
+
+    /* OPTIONAL averagingWindow */
+    // asn1cCallocOne(asn1_qosparam->qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L);
+
+    /* OPTIONAL maxDataBurstVolume */
+    // asn1cCallocOne(asn1_qosparam->qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L);
+  }
+
+  {
+    asn1_qosparam->nGRANallocationRetentionPriority.priorityLevel = drb_qos_in->alloc_reten_priority.priority_level;
+    asn1_qosparam->nGRANallocationRetentionPriority.pre_emptionCapability = drb_qos_in->alloc_reten_priority.preemption_capability;
+    asn1_qosparam->nGRANallocationRetentionPriority.pre_emptionVulnerability =
+        drb_qos_in->alloc_reten_priority.preemption_vulnerability;
+  } // nGRANallocationRetentionPriority
 
   /* OPTIONAL */
-  /* qoSPriorityLevel */
+  /* gBR_QoS_Flow_Information */
   if (0) {
-    asn1cCallocOne((*toFill)->qoSPriorityLevel, 1L);
+    asn1cCalloc(asn1_qosparam->gBR_QoS_Flow_Information, tmp);
+    asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L);
+    asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L);
+    asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L);
+    asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L);
+
+    /* OPTIONAL */
+    /* maxPacketLossRateDownlink */
+    // asn1cCallocOne(asn1_qosparam->gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L);
+
+    /* OPTIONAL */
+    /* maxPacketLossRateUplink */
+    //asn1cCallocOne(asn1_qosparam->gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L);
   }
 
   /* OPTIONAL */
-  /* averagingWindow */
+  /* reflective_QoS_Attribute */
   if (0) {
-    asn1cCallocOne((*toFill)->averagingWindow, 1L);
+    asn1cCallocOne(asn1_qosparam->reflective_QoS_Attribute, 1L);
   }
+}
+
+static void f1ap_write_drb_nssai(const nssai_t *nssai, F1AP_SNSSAI_t *asn1_nssai)
+{
+  OCTET_STRING_fromBuf(&asn1_nssai->sST, (char *)&nssai->sst, 1);
 
   /* OPTIONAL */
-  /* maxDataBurstVolume */
-  if (0) {
-    asn1cCallocOne((*toFill)->maxDataBurstVolume, 1L);
+  if (nssai->sd != 0xffffff)
+    OCTET_STRING_fromBuf(asn1_nssai->sD, (char *)&nssai->sd, 3);
+}
+
+static void f1ap_write_flows_mapped(const f1ap_flows_mapped_to_drb_t *flows_mapped, F1AP_Flows_Mapped_To_DRB_List_t *asn1_flows_mapped, int n)
+{
+  for (int k = 0; k < n; k++) {
+    asn1cSequenceAdd(asn1_flows_mapped->list, F1AP_Flows_Mapped_To_DRB_Item_t, flow_item);
+
+    const f1ap_flows_mapped_to_drb_t *qos_flow_in = flows_mapped + k;
+
+    /* qoSFlowIndicator */
+    flow_item->qoSFlowIdentifier = qos_flow_in->qfi;
+
+    /* qoSFlowLevelQoSParameters */
+    const f1ap_qos_flow_level_qos_parameters_t *flow_qos_params_in = &qos_flow_in->qos_params;
+    /* qoS_Characteristics */
+
+    F1AP_QoS_Characteristics_t *QosParams = &flow_item->qoSFlowLevelQoSParameters.qoS_Characteristics;
+    const f1ap_qos_characteristics_t *flow_qos_char_in = &flow_qos_params_in->qos_characteristics;
+
+    int type = flow_qos_params_in->qos_characteristics.qos_type;
+    if (type == non_dynamic) {
+      QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
+      asn1cCalloc(QosParams->choice.non_Dynamic_5QI, tmp);
+
+      /* 5QI */
+      tmp->fiveQI = flow_qos_char_in->non_dynamic.fiveqi;
+    } else {
+      QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
+      asn1cCalloc(QosParams->choice.dynamic_5QI, tmp);
+      /* qoSPriorityLevel */
+      tmp->qoSPriorityLevel = flow_qos_char_in->dynamic.qos_priority_level;
+      /* packetDelayBudget */
+      tmp->packetDelayBudget = flow_qos_char_in->dynamic.packet_delay_budget;
+      /* packetErrorRate */
+      tmp->packetErrorRate.pER_Scalar = flow_qos_char_in->dynamic.packet_error_rate.per_scalar;
+      tmp->packetErrorRate.pER_Exponent = flow_qos_char_in->dynamic.packet_error_rate.per_exponent;
+
+      /* OPTIONAL delayCritical */
+      //asn1cCallocOne(QosParams->choice.dynamic_5QI->delayCritical, 1);
+
+      /* OPTIONAL averagingWindow */
+      //asn1cCallocOne(QosParams->choice.dynamic_5QI->averagingWindow, 1);
+
+      /* OPTIONAL maxDataBurstVolume */
+      //asn1cCallocOne(QosParams->choice.dynamic_5QI->maxDataBurstVolume, 1);
+    }
+
+    /* nGRANallocationRetentionPriority */
+    {
+      flow_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel =
+          flow_qos_params_in->alloc_reten_priority.priority_level;
+      flow_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability =
+          flow_qos_params_in->alloc_reten_priority.preemption_capability;
+      flow_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability =
+          flow_qos_params_in->alloc_reten_priority.preemption_vulnerability;
+    } // nGRANallocationRetentionPriority
+
+    /* OPTIONAL */
+    /* gBR_QoS_Flow_Information */
+    if (0) {
+      asn1cCalloc(flow_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp);
+      asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L);
+      asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L);
+      asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L);
+      asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L);
+
+      /* OPTIONAL maxPacketLossRateDownlink */
+      //asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L);
+
+      /* OPTIONAL maxPacketLossRateUplink */
+      //asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L);
+    }
+
+    /* OPTIONAL reflective_QoS_Attribute */
+    //asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L);
   }
 }
 
@@ -275,7 +397,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
     ie12->value.present = F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List;
 
     for (int i = 0; i < f1ap_ue_context_setup_req->drbs_to_be_setup_length; i++) {
-      //
+      const f1ap_drb_to_be_setup_t *drb = &f1ap_ue_context_setup_req->drbs_to_be_setup[i];
       asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetup_List.list, F1AP_DRBs_ToBeSetup_ItemIEs_t, drbs_toBeSetup_item_ies);
       drbs_toBeSetup_item_ies->id            = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_Item;
       drbs_toBeSetup_item_ies->criticality   = F1AP_Criticality_reject;
@@ -283,7 +405,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
       /* 12.1 DRBs_ToBeSetup_Item */
       F1AP_DRBs_ToBeSetup_Item_t *drbs_toBeSetup_item=&drbs_toBeSetup_item_ies->value.choice.DRBs_ToBeSetup_Item;
       /* 12.1.1 dRBID */
-      drbs_toBeSetup_item->dRBID = f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id; // 9
+      drbs_toBeSetup_item->dRBID = drb->drb_id;
       /* 12.1.2 qoSInformation */
       int some_decide_qos = 0; // BK: Need Check
 
@@ -314,6 +436,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
         }
       } else {
         /* 12.1.2 DRB_Information */
+        const f1ap_drb_information_t *drb_info = &drb->drb_info;
         drbs_toBeSetup_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension;
         F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie));
         ie->id                             = F1AP_ProtocolIE_ID_id_DRB_Information;
@@ -321,90 +444,12 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
         ie->value.present                  = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information;
         F1AP_DRB_Information_t   *DRB_Information = &ie->value.choice.DRB_Information;
         drbs_toBeSetup_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie;
+
         /* 12.1.2.1 dRB_QoS */
-        {
-          /* qoS_Characteristics */
-          {
-            int some_decide_qoS_characteristics = 0; // BK: Need Check
-
-            if (some_decide_qoS_characteristics) {
-              DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
-              setQos(&DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI);
-            } else {
-              DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
-              asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp);
-              /* qoSPriorityLevel */
-              tmp->qoSPriorityLevel = 1L;
-              /* packetDelayBudget */
-              tmp->packetDelayBudget = 1L;
-              /* packetErrorRate */
-              tmp->packetErrorRate.pER_Scalar = 1L;
-              tmp->packetErrorRate.pER_Exponent = 6L;
-
-              /* OPTIONAL */
-              /* delayCritical */
-              if (0) {
-                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L);
-              }
-
-              /* OPTIONAL */
-              /* averagingWindow */
-              if (0) {
-                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L);
-              }
-
-              /* OPTIONAL */
-              /* maxDataBurstVolume */
-              if (0) {
-                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L);
-              }
-            } // if some_decide_qoS_characteristics
-          } // qoS_Characteristics
-          /* nGRANallocationRetentionPriority */
-          {
-            DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum
-            DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum
-            DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum
-          } // nGRANallocationRetentionPriority
-
-          /* OPTIONAL */
-          /* gBR_QoS_Flow_Information */
-          if (0) {
-            asn1cCalloc(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information, tmp);
-            asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L);
-            asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L);
-            asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L);
-            asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L);
-
-            /* OPTIONAL */
-            /* maxPacketLossRateDownlink */
-            if (0) {
-              asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L);
-            }
-
-            /* OPTIONAL */
-            /* maxPacketLossRateUplink */
-            if (0) {
-              asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L);
-            }
-          }
-
-          /* OPTIONAL */
-          /* reflective_QoS_Attribute */
-          if (0) {
-            asn1cCallocOne(DRB_Information->dRB_QoS.reflective_QoS_Attribute, 1L);
-          }
-        } // dRB_QoS
-        /* 12.1.2.2 sNSSAI */
-        {
-          /* sST */
-          OCTET_STRING_fromBuf(&DRB_Information->sNSSAI.sST, (char *)&f1ap_ue_context_setup_req->drbs_to_be_setup[i].nssai.sst, 1);
+        f1ap_write_drb_qos_param(&drb_info->drb_qos, &DRB_Information->dRB_QoS);
 
-          /* OPTIONAL */
-          const uint32_t sd = (f1ap_ue_context_setup_req->drbs_to_be_setup[i].nssai.sd & 0xffffff);
-          if (sd != 0xffffff)
-            OCTET_STRING_fromBuf(DRB_Information->sNSSAI.sD, (char *)&sd, 3);
-        }
+        /* 12.1.2.2 sNSSAI */
+        f1ap_write_drb_nssai(&drb->nssai, &DRB_Information->sNSSAI);
 
         /* OPTIONAL */
         /* 12.1.2.3 notificationControl */
@@ -414,108 +459,12 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
         }
 
         /* 12.1.2.4 flows_Mapped_To_DRB_List */  // BK: need verifiy
-
-        for (int k = 0; k < 1; k ++) {
-          asn1cSequenceAdd(DRB_Information->flows_Mapped_To_DRB_List.list,
-            F1AP_Flows_Mapped_To_DRB_Item_t, flows_mapped_to_drb_item);
-          /* qoSFlowIndicator */
-          flows_mapped_to_drb_item->qoSFlowIdentifier = 1L;
-          /* qoSFlowLevelQoSParameters */
-          {
-            /* qoS_Characteristics */
-            {
-              int some_decide_qoS_characteristics = 0; // BK: Need Check
-              F1AP_QoS_Characteristics_t *QosParams=&flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics;
-
-              if (some_decide_qoS_characteristics) {
-                QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
-                setQos(&QosParams->choice.non_Dynamic_5QI);
-              } else {
-                QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
-                asn1cCalloc(QosParams->choice.dynamic_5QI, tmp);
-                /* qoSPriorityLevel */
-                tmp->qoSPriorityLevel = 1L;
-                /* packetDelayBudget */
-                tmp->packetDelayBudget = 1L;
-                /* packetErrorRate */
-                tmp->packetErrorRate.pER_Scalar = 1L;
-                tmp->packetErrorRate.pER_Exponent = 6L;
-
-                /* OPTIONAL */
-                /* delayCritical */
-                if (0) {
-                  asn1cCalloc(QosParams->choice.dynamic_5QI->delayCritical, tmp);
-                  *tmp = 1L;
-                }
-
-                /* OPTIONAL */
-                /* averagingWindow */
-                if (0) {
-                  asn1cCalloc(QosParams->choice.dynamic_5QI->averagingWindow, tmp);
-                  *tmp = 1L;
-                }
-
-                /* OPTIONAL */
-                /* maxDataBurstVolume */
-                if (0) {
-                  asn1cCalloc(QosParams->choice.dynamic_5QI->maxDataBurstVolume, tmp);
-                  *tmp= 1L;
-                }
-              } // if some_decide_qoS_characteristics
-            } // qoS_Characteristics
-            /* nGRANallocationRetentionPriority */
-            {
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum
-            } // nGRANallocationRetentionPriority
-
-            /* OPTIONAL */
-            /* gBR_QoS_Flow_Information */
-            if (0) {
-              asn1cCalloc(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp);
-              asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L);
-              asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L);
-              asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L);
-              asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L);
-
-              /* OPTIONAL */
-              /* maxPacketLossRateDownlink */
-              if (0) {
-                asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L);
-              }
-
-              /* OPTIONAL */
-              /* maxPacketLossRateUplink */
-              if (0) {
-                asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L);
-              }
-            }
-
-            /* OPTIONAL */
-            /* reflective_QoS_Attribute */
-            if (0) {
-              asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L);
-            }
-          } // qoSFlowLevelQoSParameters
-        }
+        f1ap_write_flows_mapped(drb_info->flows_mapped_to_drb, &DRB_Information->flows_Mapped_To_DRB_List, drb_info->flows_to_be_setup_length);
       } // if some_decide_qos
 
       /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */
       for (int j = 0; j < f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) {
-        /*Use a dummy teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU*/
-        /* Use a dummy address and teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU */
-        transport_layer_addr_t addr = { .length= 32, .buffer= { 0 } };
-        f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid = newGtpuCreateTunnel(getCxt(0)->gtpInst,
-                                                                                               f1ap_ue_context_setup_req->gNB_CU_ue_id,
-                                                                                               f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id,
-                                                                                               f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id,
-                                                                                               0xFFFF, // We will set the right value from DU answer
-                                                                                               -1, // no qfi
-                                                                                               addr,   // We will set the right value from DU answer
-                                                                                               f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].port,
-                                                                                               cu_f1u_data_req,
-                                                                                               NULL);
+        DevAssert(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid > 0);
         /*  12.3.1 ULTunnels_ToBeSetup_Item */
         asn1cSequenceAdd(drbs_toBeSetup_item->uLUPTNLInformation_ToBeSetup_List.list,
           F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item);
@@ -688,11 +637,6 @@ int CU_handle_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_
       F1AP_GTPTunnel_t *dl_up_tnl0 = dl_up_tnl_info_p->dLUPTNLInformation.choice.gTPTunnel;
       BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&dl_up_tnl0->transportLayerAddress, drb_p->up_dl_tnl[0].tl_address);
       OCTET_STRING_TO_UINT32(&dl_up_tnl0->gTP_TEID, drb_p->up_dl_tnl[0].teid);
-      GtpuUpdateTunnelOutgoingAddressAndTeid(getCxt(instance)->gtpInst,
-                                             f1ap_ue_context_setup_resp->gNB_DU_ue_id,
-                                             (ebi_t)drbs_setup_item_p->dRBID,
-                                             drb_p->up_dl_tnl[0].tl_address,
-                                             drb_p->up_dl_tnl[0].teid);
     }
   }
 
@@ -1182,6 +1126,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
     ie12->value.present                  = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List;
 
     for (int i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_setup_length; i++) {
+      const f1ap_drb_to_be_setup_t *drb = &f1ap_ue_context_modification_req->drbs_to_be_setup[i];
       asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetupMod_List.list,
                      F1AP_DRBs_ToBeSetupMod_ItemIEs_t, drbs_toBeSetupMod_item_ies);
       drbs_toBeSetupMod_item_ies->id            = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item;
@@ -1191,7 +1136,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
       F1AP_DRBs_ToBeSetupMod_Item_t *drbs_toBeSetupMod_item=
           &drbs_toBeSetupMod_item_ies->value.choice.DRBs_ToBeSetupMod_Item;
       /* dRBID */
-      drbs_toBeSetupMod_item->dRBID = f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id;
+      drbs_toBeSetupMod_item->dRBID = drb->drb_id;
       /* qoSInformation */
 
       if(f1ap_ue_context_modification_req->QoS_information_type == EUTRAN_QoS){
@@ -1235,99 +1180,12 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
         ie->value.present                  = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information;
         F1AP_DRB_Information_t   *DRB_Information = &ie->value.choice.DRB_Information;
         drbs_toBeSetupMod_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie;
+
         /* 12.1.2.1 dRB_QoS */
-        {
-          /* qoS_Characteristics */
-          f1ap_qos_flow_level_qos_parameters_t *drb_qos_in = &drb_info_in->drb_qos;
-          {
-            int some_decide_qoS_characteristics = drb_qos_in->qos_characteristics.qos_type;
-
-            f1ap_qos_characteristics_t *drb_qos_char_in = &drb_qos_in->qos_characteristics;
-            if (some_decide_qoS_characteristics == non_dynamic) {
-              DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
-              asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI, tmp);
-
-              /* 5QI */
-              tmp->fiveQI = drb_qos_char_in->non_dynamic.fiveqi;
-            } else {
-              DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
-              asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp);
-              /* qoSPriorityLevel */
-              tmp->qoSPriorityLevel = drb_qos_char_in->dynamic.qos_priority_level;
-              /* packetDelayBudget */
-              tmp->packetDelayBudget = drb_qos_char_in->dynamic.packet_delay_budget;
-              /* packetErrorRate */
-              tmp->packetErrorRate.pER_Scalar = drb_qos_char_in->dynamic.packet_error_rate.per_scalar;
-              tmp->packetErrorRate.pER_Exponent = drb_qos_char_in->dynamic.packet_error_rate.per_scalar;
-
-              /* OPTIONAL */
-              /* delayCritical */
-              if (0) {
-                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L);
-              }
-
-              /* OPTIONAL */
-              /* averagingWindow */
-              if (0) {
-                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L);
-              }
-
-              /* OPTIONAL */
-              /* maxDataBurstVolume */
-              if (0) {
-                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L);
-              }
-            } // if some_decide_qoS_characteristics
-
-            } // qoS_Characteristics
-            /* nGRANallocationRetentionPriority */
-            {
-              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel =
-                  drb_qos_in->alloc_reten_priority.priority_level;
-              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability =
-                  drb_qos_in->alloc_reten_priority.preemption_capability;
-              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability =
-                  drb_qos_in->alloc_reten_priority.preemption_vulnerability;
-            } // nGRANallocationRetentionPriority
-
-          /* OPTIONAL */
-          /* gBR_QoS_Flow_Information */
-          if (0) {
-            asn1cCalloc(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information, tmp);
-            asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L);
-            asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L);
-            asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L);
-            asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L);
-
-            /* OPTIONAL */
-            /* maxPacketLossRateDownlink */
-            if (0) {
-              asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L);
-            }
-
-            /* OPTIONAL */
-            /* maxPacketLossRateUplink */
-            if (0) {
-              asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L);
-            }
-          }
-
-          /* OPTIONAL */
-          /* reflective_QoS_Attribute */
-          if (0) {
-            asn1cCallocOne(DRB_Information->dRB_QoS.reflective_QoS_Attribute, 1L);
-          }
-        } // dRB_QoS
-        /* 12.1.2.2 sNSSAI */
-        {
-          /* sST */
-          OCTET_STRING_fromBuf(&DRB_Information->sNSSAI.sST, (char *)&f1ap_ue_context_modification_req->drbs_to_be_setup[i].nssai.sst, 1);
+        f1ap_write_drb_qos_param(&drb_info_in->drb_qos, &DRB_Information->dRB_QoS);
 
-          /* OPTIONAL */
-          const uint32_t sd = (f1ap_ue_context_modification_req->drbs_to_be_setup[i].nssai.sd & 0xffffff);
-          if (sd != 0xffffff)
-            OCTET_STRING_fromBuf(DRB_Information->sNSSAI.sD, (char *)&sd, 3);
-        }
+        /* 12.1.2.2 sNSSAI */
+        f1ap_write_drb_nssai(&drb->nssai, &DRB_Information->sNSSAI);
 
         /* OPTIONAL */
         /* 12.1.2.3 notificationControl */
@@ -1337,102 +1195,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
         }
 
         /* 12.1.2.4 flows_Mapped_To_DRB_List */
-        for (int k = 0; k < drb_info_in->flows_to_be_setup_length; k++) {
-          asn1cSequenceAdd(DRB_Information->flows_Mapped_To_DRB_List.list,
-                         F1AP_Flows_Mapped_To_DRB_Item_t, flows_mapped_to_drb_item);
-
-          f1ap_flows_mapped_to_drb_t *qos_flow_in = drb_info_in->flows_mapped_to_drb + k;
-
-          /* qoSFlowIndicator */
-          flows_mapped_to_drb_item->qoSFlowIdentifier = qos_flow_in->qfi;
-          /* qoSFlowLevelQoSParameters */
-          {
-            f1ap_qos_flow_level_qos_parameters_t *flow_qos_params_in = &qos_flow_in->qos_params;
-            /* qoS_Characteristics */
-            {
-              int some_decide_qoS_characteristics = flow_qos_params_in->qos_characteristics.qos_type;
-              F1AP_QoS_Characteristics_t *QosParams = &flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics;
-              f1ap_qos_characteristics_t *flow_qos_char_in = &flow_qos_params_in->qos_characteristics;
-
-              if (some_decide_qoS_characteristics == non_dynamic) {
-                QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
-                asn1cCalloc(QosParams->choice.non_Dynamic_5QI, tmp);
-
-                /* 5QI */
-                tmp->fiveQI = flow_qos_char_in->non_dynamic.fiveqi;
-              } else {
-                QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
-                asn1cCalloc(QosParams->choice.dynamic_5QI, tmp);
-                /* qoSPriorityLevel */
-                tmp->qoSPriorityLevel = flow_qos_char_in->dynamic.qos_priority_level;
-                /* packetDelayBudget */
-                tmp->packetDelayBudget = flow_qos_char_in->dynamic.packet_delay_budget;
-                /* packetErrorRate */
-                tmp->packetErrorRate.pER_Scalar = flow_qos_char_in->dynamic.packet_error_rate.per_scalar;
-                tmp->packetErrorRate.pER_Exponent = flow_qos_char_in->dynamic.packet_error_rate.per_exponent;
-
-                /* OPTIONAL */
-                /* delayCritical */
-                if (0) {
-                  asn1cCalloc(QosParams->choice.dynamic_5QI->delayCritical, tmp);
-                  *tmp = 1L;
-                }
-
-                /* OPTIONAL */
-                /* averagingWindow */
-                if (0) {
-                  asn1cCalloc(QosParams->choice.dynamic_5QI->averagingWindow, tmp);
-                  *tmp = 1L;
-                }
-
-                /* OPTIONAL */
-                /* maxDataBurstVolume */
-                if (0) {
-                  asn1cCalloc(QosParams->choice.dynamic_5QI->maxDataBurstVolume, tmp);
-                  *tmp= 1L;
-                }
-              } // if some_decide_qoS_characteristics
-
-            } // qoS_Characteristics
-            /* nGRANallocationRetentionPriority */
-            {
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel =
-                  flow_qos_params_in->alloc_reten_priority.priority_level;
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability =
-                  flow_qos_params_in->alloc_reten_priority.preemption_capability;
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability =
-                  flow_qos_params_in->alloc_reten_priority.preemption_vulnerability;
-            } // nGRANallocationRetentionPriority
-
-            /* OPTIONAL */
-            /* gBR_QoS_Flow_Information */
-            if (0) {
-              asn1cCalloc(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp);
-              asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L);
-              asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L);
-              asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L);
-              asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L);
-
-              /* OPTIONAL */
-              /* maxPacketLossRateDownlink */
-              if (0) {
-                asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L);
-              }
-
-              /* OPTIONAL */
-              /* maxPacketLossRateUplink */
-              if (0) {
-                asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L);
-              }
-            }
-
-            /* OPTIONAL */
-            /* reflective_QoS_Attribute */
-            if (0) {
-              asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L);
-            }
-          } // qoSFlowLevelQoSParameters
-        }
+        f1ap_write_flows_mapped(drb_info_in->flows_mapped_to_drb, &DRB_Information->flows_Mapped_To_DRB_List, drb_info_in->flows_to_be_setup_length);
 
       } //QoS information
 
@@ -1569,9 +1332,6 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
           &drbs_toBeReleased_item_ies->value.choice.DRBs_ToBeReleased_Item;
       /* dRBID */
       drbs_toBeReleased_item->dRBID = f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id;
-      newGtpuDeleteOneTunnel(getCxt(0)->gtpInst,
-                             f1ap_ue_context_modification_req->gNB_CU_ue_id,
-                             f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id);
     }
   }
 
@@ -1644,11 +1404,6 @@ int CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, sctp_assoc_t
         F1AP_GTPTunnel_t *dl_up_tnl0 = dl_up_tnl_info_p->dLUPTNLInformation.choice.gTPTunnel;
         BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&dl_up_tnl0->transportLayerAddress, drb_p->up_dl_tnl[0].tl_address);
         OCTET_STRING_TO_UINT32(&dl_up_tnl0->gTP_TEID, drb_p->up_dl_tnl[0].teid);
-        GtpuUpdateTunnelOutgoingAddressAndTeid(getCxt(instance)->gtpInst,
-                     f1ap_ue_context_modification_resp->gNB_CU_ue_id,
-                     (ebi_t)drbs_setupmod_item_p->dRBID,
-                     drb_p->up_dl_tnl[0].tl_address,
-                     drb_p->up_dl_tnl[0].teid);
       }
     }
     // SRBs_FailedToBeSetupMod_List
diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.c b/openair2/F1AP/f1ap_du_rrc_message_transfer.c
index 3a2f7ce7250bec848674cfb23442b92b3542f6f2..4a3526dd0a659b2c1f940cc28095b343ef8994e1 100644
--- a/openair2/F1AP/f1ap_du_rrc_message_transfer.c
+++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.c
@@ -50,7 +50,6 @@
 #include "asn1_msg.h"
 #include "intertask_interface.h"
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
-#include <openair3/ocp-gtpu/gtp_itf.h>
 
 #include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
 
@@ -83,7 +82,6 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id
     /* strange: it is not named OLD_GNB_DU_UE... */
     old_gNB_DU_ue_id_stack = ie->value.choice.GNB_DU_UE_F1AP_ID_1;
     old_gNB_DU_ue_id = &old_gNB_DU_ue_id_stack;
-    gtpv1u_update_ue_id(getCxt(instance)->gtpInst, old_gNB_DU_ue_id_stack, du_ue_f1ap_id);
   }
 
   /* mandatory */
diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c
index d823a350925a817a2e12a1ca235599c22e301977..c2f690107c3e146c8db7c3d0934e1c857009e54c 100644
--- a/openair2/F1AP/f1ap_du_task.c
+++ b/openair2/F1AP/f1ap_du_task.c
@@ -40,6 +40,16 @@
 //Fixme: Uniq dirty DU instance, by global var, datamodel need better management
 instance_t DUuniqInstance=0;
 
+static instance_t du_create_gtpu_instance_to_cu(const f1ap_net_config_t *nc)
+{
+  openAddr_t tmp = {0};
+  strncpy(tmp.originHost, nc->DU_f1_ip_address.ipv4_address, sizeof(tmp.originHost) - 1);
+  strncpy(tmp.destinationHost, nc->CU_f1_ip_address.ipv4_address, sizeof(tmp.destinationHost) - 1);
+  sprintf(tmp.originService, "%d", nc->DUport);
+  sprintf(tmp.destinationService, "%d", nc->CUport);
+  return gtpv1Init(tmp);
+}
+
 void du_task_send_sctp_association_req(instance_t instance, f1ap_net_config_t *nc)
 {
   DevAssert(nc != NULL);
@@ -116,6 +126,10 @@ void *F1AP_DU_task(void *arg) {
         f1ap_net_config_t *nc = &F1AP_DU_REGISTER_REQ(msg).net_config;
         createF1inst(myInstance, msgSetup, nc);
         du_task_send_sctp_association_req(myInstance, nc);
+        instance_t gtpInst = du_create_gtpu_instance_to_cu(nc);
+        AssertFatal(gtpInst != 0, "cannot create DU F1-U GTP module\n");
+        getCxt(myInstance)->gtpInst = gtpInst;
+        DUuniqInstance = gtpInst;
       } break;
 
       case F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE:
diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c
index e306463b667ac6ee5d62d345ac57d74f29d33313..3715c0ae5def2ed156e74a80494a9e3775b2ad45 100644
--- a/openair2/F1AP/f1ap_du_ue_context_management.c
+++ b/openair2/F1AP/f1ap_du_ue_context_management.c
@@ -37,25 +37,82 @@
 #include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
 
 #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
-#include <openair3/ocp-gtpu/gtp_itf.h>
 #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
 
-bool DURecvCb(protocol_ctxt_t *ctxt_pP,
-              const srb_flag_t srb_flagP,
-              const rb_id_t rb_idP,
-              const mui_t muiP,
-              const confirm_t confirmP,
-              const sdu_size_t sdu_buffer_sizeP,
-              unsigned char *const sdu_buffer_pP,
-              const pdcp_transmission_mode_t modeP,
-              const uint32_t *sourceL2Id,
-              const uint32_t *destinationL2Id)
+static void f1ap_read_drb_qos_param(const F1AP_QoSFlowLevelQoSParameters_t *asn1_qos, f1ap_qos_flow_level_qos_parameters_t *drb_qos)
 {
-  // The buffer comes from the stack in gtp-u thread, we have a make a separate buffer to enqueue in a inter-thread message queue
-  uint8_t *sdu = malloc16(sdu_buffer_sizeP);
-  memcpy(sdu, sdu_buffer_pP, sdu_buffer_sizeP);
-  du_rlc_data_req(ctxt_pP, srb_flagP, false, rb_idP, muiP, confirmP, sdu_buffer_sizeP, sdu);
-  return true;
+  f1ap_qos_characteristics_t *drb_qos_char = &drb_qos->qos_characteristics;
+  const F1AP_QoS_Characteristics_t *dRB_QoS_Char = &asn1_qos->qoS_Characteristics;
+
+  if (dRB_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
+    drb_qos_char->qos_type = non_dynamic;
+    drb_qos_char->non_dynamic.fiveqi = dRB_QoS_Char->choice.non_Dynamic_5QI->fiveQI;
+    drb_qos_char->non_dynamic.qos_priority_level = (dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL)
+                                                       ? *dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel
+                                                       : -1;
+  } else {
+    drb_qos_char->qos_type = dynamic;
+    drb_qos_char->dynamic.fiveqi =
+        (dRB_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *dRB_QoS_Char->choice.dynamic_5QI->fiveQI : -1;
+    drb_qos_char->dynamic.qos_priority_level = dRB_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel;
+    drb_qos_char->dynamic.packet_delay_budget = dRB_QoS_Char->choice.dynamic_5QI->packetDelayBudget;
+    drb_qos_char->dynamic.packet_error_rate.per_scalar = dRB_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Scalar;
+    drb_qos_char->dynamic.packet_error_rate.per_exponent = dRB_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Exponent;
+  }
+
+  /* nGRANallocationRetentionPriority */
+  drb_qos->alloc_reten_priority.priority_level = asn1_qos->nGRANallocationRetentionPriority.priorityLevel;
+  drb_qos->alloc_reten_priority.preemption_vulnerability = asn1_qos->nGRANallocationRetentionPriority.pre_emptionVulnerability;
+  drb_qos->alloc_reten_priority.preemption_capability = asn1_qos->nGRANallocationRetentionPriority.pre_emptionVulnerability;
+}
+
+static void f1ap_read_flows_mapped(const F1AP_Flows_Mapped_To_DRB_List_t *asn1_flows_mapped, f1ap_flows_mapped_to_drb_t *flows_mapped, int n)
+{
+  for (int k = 0; k < n; k++) {
+    f1ap_flows_mapped_to_drb_t *flows_mapped_to_drb = flows_mapped + k;
+    const F1AP_Flows_Mapped_To_DRB_Item_t *flows_Mapped_To_Drb = asn1_flows_mapped->list.array[0] + k;
+
+    flows_mapped_to_drb->qfi = flows_Mapped_To_Drb->qoSFlowIdentifier;
+
+    /* QoS-Flow-Level-QoS-Parameters */
+    {
+      f1ap_qos_flow_level_qos_parameters_t *flow_qos = &flows_mapped_to_drb->qos_params;
+      const F1AP_QoSFlowLevelQoSParameters_t *Flow_QoS = &flows_Mapped_To_Drb->qoSFlowLevelQoSParameters;
+
+      /* QoS Characteristics*/
+      f1ap_qos_characteristics_t *flow_qos_char = &flow_qos->qos_characteristics;
+      const F1AP_QoS_Characteristics_t *Flow_QoS_Char = &Flow_QoS->qoS_Characteristics;
+
+      if (Flow_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
+        flow_qos_char->qos_type = non_dynamic;
+        flow_qos_char->non_dynamic.fiveqi = Flow_QoS_Char->choice.non_Dynamic_5QI->fiveQI;
+        flow_qos_char->non_dynamic.qos_priority_level = (Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL)
+                                                            ? *Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel
+                                                            : -1;
+      } else {
+        flow_qos_char->qos_type = dynamic;
+        flow_qos_char->dynamic.fiveqi =
+            (Flow_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *Flow_QoS_Char->choice.dynamic_5QI->fiveQI : -1;
+        flow_qos_char->dynamic.qos_priority_level = Flow_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel;
+        flow_qos_char->dynamic.packet_delay_budget = Flow_QoS_Char->choice.dynamic_5QI->packetDelayBudget;
+        flow_qos_char->dynamic.packet_error_rate.per_scalar = Flow_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Scalar;
+        flow_qos_char->dynamic.packet_error_rate.per_exponent = Flow_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Exponent;
+      }
+
+      /* nGRANallocationRetentionPriority */
+      flow_qos->alloc_reten_priority.priority_level = Flow_QoS->nGRANallocationRetentionPriority.priorityLevel;
+      flow_qos->alloc_reten_priority.preemption_vulnerability = Flow_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
+      flow_qos->alloc_reten_priority.preemption_capability = Flow_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
+    }
+  }
+}
+
+static void f1ap_read_drb_nssai(const F1AP_SNSSAI_t *asn1_nssai, nssai_t *nssai)
+{
+  OCTET_STRING_TO_INT8(&asn1_nssai->sST, nssai->sst);
+  nssai->sd = 0xffffff;
+  if (asn1_nssai->sD != NULL)
+    memcpy((uint8_t *)&nssai->sd, asn1_nssai->sD->buf, 3);
 }
 
 int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu)
@@ -159,6 +216,36 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i
           drb_p->rlc_mode = RLC_MODE_TM;
           break;
       }
+
+      if (drbs_tobesetup_item_p->qoSInformation.present == F1AP_QoSInformation_PR_eUTRANQoS) {
+        AssertFatal(false, "Decode of eUTRANQoS is not implemented yet");
+      } // EUTRAN QoS Information
+      else {
+        /* 12.1.2 DRB_Information */
+        if (drbs_tobesetup_item_p->qoSInformation.present == F1AP_QoSInformation_PR_choice_extension) {
+          F1AP_QoSInformation_ExtIEs_t *ie =
+              (F1AP_QoSInformation_ExtIEs_t *)drbs_tobesetup_item_p->qoSInformation.choice.choice_extension;
+          if (ie->id == F1AP_ProtocolIE_ID_id_DRB_Information && ie->criticality == F1AP_Criticality_reject
+              && ie->value.present == F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information) {
+
+            const F1AP_DRB_Information_t *dRB_Info = &ie->value.choice.DRB_Information;
+            f1ap_drb_information_t *drb_info = &drb_p->drb_info;
+
+            /* QoS-Flow-Level-QoS-Parameters */
+            /* QoS Characteristics*/
+            f1ap_read_drb_qos_param(&dRB_Info->dRB_QoS, &drb_info->drb_qos);
+
+            // 12.1.2.4 flows_Mapped_To_DRB_List
+            drb_info->flows_to_be_setup_length = dRB_Info->flows_Mapped_To_DRB_List.list.count;
+            drb_info->flows_mapped_to_drb = calloc(drb_info->flows_to_be_setup_length, sizeof(f1ap_flows_mapped_to_drb_t));
+            AssertFatal(drb_info->flows_mapped_to_drb, "could not allocate memory for drb_p->drb_info.flows_mapped_to_drb\n");
+            f1ap_read_flows_mapped(&dRB_Info->flows_Mapped_To_DRB_List, drb_info->flows_mapped_to_drb, drb_info->flows_to_be_setup_length);
+
+            /* S-NSSAI */
+            f1ap_read_drb_nssai(&dRB_Info->sNSSAI, &drb_p->nssai);
+          }
+        }
+      }
     }
   }
 
@@ -305,6 +392,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set
     ie7->criticality                    = F1AP_Criticality_ignore;
     ie7->value.present                  = F1AP_UEContextSetupResponseIEs__value_PR_DRBs_Setup_List;
     for (int i=0;  i< resp->drbs_to_be_setup_length; i++) {
+      f1ap_drb_to_be_setup_t *drb = &resp->drbs_to_be_setup[i];
       //
       asn1cSequenceAdd(ie7->value.choice.DRBs_Setup_List.list,
           F1AP_DRBs_Setup_ItemIEs_t, drbs_setup_item_ies);
@@ -315,14 +403,17 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set
       /* ADD */
       F1AP_DRBs_Setup_Item_t *drbs_setup_item=&drbs_setup_item_ies->value.choice.DRBs_Setup_Item;
       /* dRBID */
-      drbs_setup_item->dRBID = resp->drbs_to_be_setup[i].drb_id;
+      drbs_setup_item->dRBID = drb->drb_id;
 
       /* OPTIONAL */
       /* lCID */
       //drbs_setup_item.lCID = (F1AP_LCID_t *)calloc(1, sizeof(F1AP_LCID_t));
       //drbs_setup_item.lCID = 1L;
 
-      for (int j=0;  j<resp->drbs_to_be_setup[i].up_dl_tnl_length; j++) {
+      for (int j = 0;  j < drb->up_dl_tnl_length; j++) {
+        const f1ap_up_tnl_t *tnl = &drb->up_dl_tnl[j];
+        DevAssert(tnl->teid > 0);
+
         /* ADD */
         asn1cSequenceAdd(drbs_setup_item->dLUPTNLInformation_ToBeSetup_List.list,
                        F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item);
@@ -330,12 +421,9 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set
         /* gTPTunnel */
         asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel);
         /* transportLayerAddress */
-        struct sockaddr_in addr= {0};
-        inet_pton(AF_INET, getCxt(0)->net_config.DU_f1_ip_address.ipv4_address, &addr.sin_addr.s_addr);
-        TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr,
-            &gTPTunnel->transportLayerAddress);
+        TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(tnl->tl_address, &gTPTunnel->transportLayerAddress);
         /* gTP_TEID */
-        INT32_TO_OCTET_STRING(resp->drbs_to_be_setup[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID);
+        INT32_TO_OCTET_STRING(tnl->teid, &gTPTunnel->gTP_TEID);
       } // for j
     } // for i
 
@@ -772,16 +860,6 @@ int DU_send_UE_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, f1ap_ue_context_r
   return 0;
 }
 
-static instance_t du_create_gtpu_instance_to_cu(char *CUaddr, uint16_t CUport, char *DUaddr, uint16_t DUport)
-{
-  openAddr_t tmp = {0};
-  strncpy(tmp.originHost, DUaddr, sizeof(tmp.originHost)-1);
-  strncpy(tmp.destinationHost, CUaddr, sizeof(tmp.destinationHost)-1);
-  sprintf(tmp.originService, "%d", DUport);
-  sprintf(tmp.destinationService, "%d", CUport);
-  return gtpv1Init(tmp);
-}
-
 int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu)
 {
   F1AP_UEContextModificationRequest_t    *container;
@@ -853,27 +931,6 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t
        // 3GPP assumes GTP-U is on port 2152, but OAI is configurable
       drb_p->up_ul_tnl[0].port = getCxt(instance)->net_config.CUport;
 
-      extern instance_t DUuniqInstance;
-      if (DUuniqInstance == 0) {
-        char gtp_tunnel_ip_address[32];
-        snprintf(gtp_tunnel_ip_address,
-                 sizeof(gtp_tunnel_ip_address),
-                 "%d.%d.%d.%d",
-                 drb_p->up_ul_tnl[0].tl_address & 0xff,
-                 (drb_p->up_ul_tnl[0].tl_address >> 8) & 0xff,
-                 (drb_p->up_ul_tnl[0].tl_address >> 16) & 0xff,
-                 (drb_p->up_ul_tnl[0].tl_address >> 24) & 0xff);
-        getCxt(instance)->gtpInst = du_create_gtpu_instance_to_cu(gtp_tunnel_ip_address,
-                                                                  getCxt(instance)->net_config.CUport,
-                                                                  getCxt(instance)->net_config.DU_f1_ip_address.ipv4_address,
-                                                                  getCxt(instance)->net_config.DUport);
-        AssertFatal(getCxt(instance)->gtpInst > 0, "Failed to create CU F1-U UDP listener");
-        // Fixme: fully inconsistent instances management
-        // dirty global var is a bad fix
-        extern instance_t legacyInstanceMapping;
-        legacyInstanceMapping = DUuniqInstance = getCxt(instance)->gtpInst;
-      }
-
       switch (drbs_tobesetupmod_item_p->rLCMode) {
       case F1AP_RLCMode_rlc_am:
         drb_p->rlc_mode = RLC_MODE_AM;
@@ -894,101 +951,22 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t
               (F1AP_QoSInformation_ExtIEs_t *)drbs_tobesetupmod_item_p->qoSInformation.choice.choice_extension;
           if (ie->id == F1AP_ProtocolIE_ID_id_DRB_Information && ie->criticality == F1AP_Criticality_reject
               && ie->value.present == F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information) {
-            F1AP_DRB_Information_t *dRB_Info = &ie->value.choice.DRB_Information;
-            f1ap_drb_information_t *drb_info = &f1ap_ue_context_modification_req->drbs_to_be_setup->drb_info;
-
-            /* 12.1.2.1 dRB_QoS */
-            {
-              /* QoS-Flow-Level-QoS-Parameters */
-              f1ap_qos_flow_level_qos_parameters_t *drb_qos = &drb_info->drb_qos;
-              F1AP_QoSFlowLevelQoSParameters_t *dRB_QoS = &dRB_Info->dRB_QoS;
-              {
-                /* QoS Characteristics*/
-                f1ap_qos_characteristics_t *drb_qos_char = &drb_qos->qos_characteristics;
-                F1AP_QoS_Characteristics_t *dRB_QoS_Char = &dRB_QoS->qoS_Characteristics;
-
-                if (dRB_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
-                  drb_qos_char->qos_type = non_dynamic;
-                  drb_qos_char->non_dynamic.fiveqi = dRB_QoS_Char->choice.non_Dynamic_5QI->fiveQI;
-                  drb_qos_char->non_dynamic.qos_priority_level = (dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL)
-                                                                     ? *dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel
-                                                                     : -1;
-                } else {
-                  drb_qos_char->qos_type = dynamic;
-                  drb_qos_char->dynamic.fiveqi =
-                      (dRB_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *dRB_QoS_Char->choice.dynamic_5QI->fiveQI : -1;
-                  drb_qos_char->dynamic.qos_priority_level = dRB_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel;
-                  drb_qos_char->dynamic.packet_delay_budget = dRB_QoS_Char->choice.dynamic_5QI->packetDelayBudget;
-                  drb_qos_char->dynamic.packet_error_rate.per_scalar = dRB_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Scalar;
-                  drb_qos_char->dynamic.packet_error_rate.per_exponent =
-                      dRB_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Exponent;
-                }
-              }
-
-              /* nGRANallocationRetentionPriority */
-              drb_qos->alloc_reten_priority.priority_level = dRB_QoS->nGRANallocationRetentionPriority.priorityLevel;
-              drb_qos->alloc_reten_priority.preemption_vulnerability =
-                  dRB_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
-              drb_qos->alloc_reten_priority.preemption_capability =
-                  dRB_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
-            } // dRB_QoS
+
+            const F1AP_DRB_Information_t *dRB_Info = &ie->value.choice.DRB_Information;
+            f1ap_drb_information_t *drb_info = &drb_p->drb_info;
+
+            /* QoS-Flow-Level-QoS-Parameters */
+            /* QoS Characteristics*/
+            f1ap_read_drb_qos_param(&dRB_Info->dRB_QoS, &drb_info->drb_qos);
 
             // 12.1.2.4 flows_Mapped_To_DRB_List
             drb_info->flows_to_be_setup_length = dRB_Info->flows_Mapped_To_DRB_List.list.count;
             drb_info->flows_mapped_to_drb = calloc(drb_info->flows_to_be_setup_length, sizeof(f1ap_flows_mapped_to_drb_t));
             AssertFatal(drb_info->flows_mapped_to_drb, "could not allocate memory for drb_p->drb_info.flows_mapped_to_drb\n");
-
-            for (int k = 0; k < drb_p->drb_info.flows_to_be_setup_length; k++) {
-              f1ap_flows_mapped_to_drb_t *flows_mapped_to_drb = drb_info->flows_mapped_to_drb + k;
-              F1AP_Flows_Mapped_To_DRB_Item_t *flows_Mapped_To_Drb = dRB_Info->flows_Mapped_To_DRB_List.list.array[0] + k;
-
-              flows_mapped_to_drb->qfi = flows_Mapped_To_Drb->qoSFlowIdentifier;
-
-              /* QoS-Flow-Level-QoS-Parameters */
-              {
-                f1ap_qos_flow_level_qos_parameters_t *flow_qos = &flows_mapped_to_drb->qos_params;
-                F1AP_QoSFlowLevelQoSParameters_t *Flow_QoS = &flows_Mapped_To_Drb->qoSFlowLevelQoSParameters;
-
-                /* QoS Characteristics*/
-                {
-                  f1ap_qos_characteristics_t *flow_qos_char = &flow_qos->qos_characteristics;
-                  F1AP_QoS_Characteristics_t *Flow_QoS_Char = &Flow_QoS->qoS_Characteristics;
-
-                  if (Flow_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
-                    flow_qos_char->qos_type = non_dynamic;
-                    flow_qos_char->non_dynamic.fiveqi = Flow_QoS_Char->choice.non_Dynamic_5QI->fiveQI;
-                    flow_qos_char->non_dynamic.qos_priority_level =
-                        (Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL)
-                            ? *Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel
-                            : -1;
-                  } else {
-                    flow_qos_char->qos_type = dynamic;
-                    flow_qos_char->dynamic.fiveqi =
-                        (Flow_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *Flow_QoS_Char->choice.dynamic_5QI->fiveQI : -1;
-                    flow_qos_char->dynamic.qos_priority_level = Flow_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel;
-                    flow_qos_char->dynamic.packet_delay_budget = Flow_QoS_Char->choice.dynamic_5QI->packetDelayBudget;
-                    flow_qos_char->dynamic.packet_error_rate.per_scalar =
-                        Flow_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Scalar;
-                    flow_qos_char->dynamic.packet_error_rate.per_exponent =
-                        Flow_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Exponent;
-                  }
-                }
-
-                /* nGRANallocationRetentionPriority */
-                flow_qos->alloc_reten_priority.priority_level = Flow_QoS->nGRANallocationRetentionPriority.priorityLevel;
-                flow_qos->alloc_reten_priority.preemption_vulnerability =
-                    Flow_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
-                flow_qos->alloc_reten_priority.preemption_capability =
-                    Flow_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
-              }
-            }
+            f1ap_read_flows_mapped(&dRB_Info->flows_Mapped_To_DRB_List, drb_info->flows_mapped_to_drb, drb_info->flows_to_be_setup_length);
 
             /* S-NSSAI */
-            OCTET_STRING_TO_INT8(&dRB_Info->sNSSAI.sST, drb_p->nssai.sst);
-            if (dRB_Info->sNSSAI.sD != NULL)
-              memcpy((uint8_t *)&drb_p->nssai.sd, dRB_Info->sNSSAI.sD->buf, 3);
-            else
-              drb_p->nssai.sd = 0xffffff;
+            f1ap_read_drb_nssai(&dRB_Info->sNSSAI, &drb_p->nssai);
           }
         }
       }
@@ -1008,7 +986,6 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t
       DevAssert(tbrel->id == F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item);
       DevAssert(tbrel->value.present == F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item);
       f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id = tbrel->value.choice.DRBs_ToBeReleased_Item.dRBID;
-      newGtpuDeleteOneTunnel(0, f1ap_ue_context_modification_req->gNB_DU_ue_id, f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id);
     }
   }
 
@@ -1166,20 +1143,8 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_cont
       drbs_setupmod_item->dRBID = resp->drbs_to_be_setup[i].drb_id;
 
       for (int j=0;  j<resp->drbs_to_be_setup[i].up_dl_tnl_length; j++) {
-        f1ap_drb_to_be_setup_t *drb = &resp->drbs_to_be_setup[i];
-        transport_layer_addr_t tl_addr = {0};
-        memcpy(tl_addr.buffer, &drb->up_ul_tnl[0].tl_address, sizeof(drb->up_ul_tnl[0].tl_address));
-        tl_addr.length = sizeof(drb->up_ul_tnl[0].tl_address) * 8;
-        drb->up_dl_tnl[j].teid = newGtpuCreateTunnel(getCxt(0)->gtpInst,
-                                                     resp->gNB_DU_ue_id,
-                                                     drb->drb_id,
-                                                     drb->drb_id,
-                                                     drb->up_ul_tnl[j].teid,
-                                                     -1, // no qfi
-                                                     tl_addr,
-                                                     drb->up_ul_tnl[0].port,
-                                                     DURecvCb,
-                                                     NULL);
+        const f1ap_up_tnl_t *tnl = &resp->drbs_to_be_setup[i].up_dl_tnl[j];
+        DevAssert(tnl->teid > 0);
 
         /* ADD */
         asn1cSequenceAdd(drbs_setupmod_item->dLUPTNLInformation_ToBeSetup_List.list,
@@ -1188,12 +1153,9 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_cont
         /* gTPTunnel */
         asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel);
         /* transportLayerAddress */
-        struct sockaddr_in addr= {0};
-        inet_pton(AF_INET, getCxt(0)->net_config.DU_f1_ip_address.ipv4_address, &addr.sin_addr.s_addr);
-        TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr,
-          &gTPTunnel->transportLayerAddress);
+        TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(tnl->tl_address, &gTPTunnel->transportLayerAddress);
         /* gTP_TEID */
-        INT32_TO_OCTET_STRING(resp->drbs_to_be_setup[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID);
+        INT32_TO_OCTET_STRING(tnl->teid, &gTPTunnel->gTP_TEID);
       } // for j
     } // for i
   }
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
index 04f2c2fdc918e6e011542dde55ecd7f1f788d3cd..d537865de5b66fb4850e6a182d85f08dd740df92 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
@@ -23,8 +23,11 @@
 
 #include "mac_proto.h"
 #include "openair2/F1AP/f1ap_ids.h"
+#include "openair2/F1AP/f1ap_common.h"
 #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
 #include "F1AP_CauseRadioNetwork.h"
+#include "openair3/ocp-gtpu/gtp_itf.h"
+#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
 
 #include "uper_decoder.h"
 #include "uper_encoder.h"
@@ -34,6 +37,59 @@ const uint64_t qos_fiveqi[26] = {1, 2, 3, 4, 65, 66, 67, 71, 72, 73, 74, 76, 5,
 const uint64_t qos_priority[26] = {20, 40, 30, 50, 7, 20, 15, 56, 56, 56, 56, 56, 10,
                                    60, 70, 80, 90, 5, 55, 65, 68, 19, 22, 24, 21, 18};
 
+static instance_t get_f1_gtp_instance(void)
+{
+  const f1ap_cudu_inst_t *inst = getCxt(0);
+  if (!inst)
+    return -1; // means no F1
+  return inst->gtpInst;
+}
+
+static int drb_gtpu_create(instance_t instance,
+                           uint32_t ue_id,
+                           int incoming_id,
+                           int outgoing_id,
+                           int qfi,
+                           in_addr_t tlAddress, // only IPv4 now
+                           teid_t outgoing_teid,
+                           gtpCallback callBack,
+                           gtpCallbackSDAP callBackSDAP,
+                           gtpv1u_gnb_create_tunnel_resp_t *create_tunnel_resp)
+{
+  gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0};
+  create_tunnel_req.incoming_rb_id[0] = incoming_id;
+  create_tunnel_req.pdusession_id[0] = outgoing_id;
+  memcpy(&create_tunnel_req.dst_addr[0].buffer, &tlAddress, sizeof(uint8_t) * 4);
+  create_tunnel_req.dst_addr[0].length = 32;
+  create_tunnel_req.outgoing_teid[0] = outgoing_teid;
+  create_tunnel_req.outgoing_qfi[0] = qfi;
+  create_tunnel_req.num_tunnels = 1;
+  create_tunnel_req.ue_id = ue_id;
+
+  // we use gtpv1u_create_ngu_tunnel because it returns the interface
+  // address and port of the interface; apart from that, we also might call
+  // newGtpuCreateTunnel() directly
+  return gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, create_tunnel_resp, callBack, callBackSDAP);
+}
+
+bool DURecvCb(protocol_ctxt_t *ctxt_pP,
+              const srb_flag_t srb_flagP,
+              const rb_id_t rb_idP,
+              const mui_t muiP,
+              const confirm_t confirmP,
+              const sdu_size_t sdu_buffer_sizeP,
+              unsigned char *const sdu_buffer_pP,
+              const pdcp_transmission_mode_t modeP,
+              const uint32_t *sourceL2Id,
+              const uint32_t *destinationL2Id)
+{
+  // The buffer comes from the stack in gtp-u thread, we have a make a separate buffer to enqueue in a inter-thread message queue
+  uint8_t *sdu = malloc16(sdu_buffer_sizeP);
+  memcpy(sdu, sdu_buffer_pP, sdu_buffer_sizeP);
+  du_rlc_data_req(ctxt_pP, srb_flagP, false, rb_idP, muiP, confirmP, sdu_buffer_sizeP, sdu);
+  return true;
+}
+
 static long get_lcid_from_drbid(int drb_id)
 {
   return drb_id + 3; /* LCID is DRB + 3 */
@@ -133,6 +189,7 @@ static int handle_ue_context_drbs_setup(int rnti,
                                         NR_CellGroupConfig_t *cellGroupConfig)
 {
   DevAssert(req_drbs != NULL && resp_drbs != NULL && cellGroupConfig != NULL);
+  instance_t f1inst = get_f1_gtp_instance();
 
   /* Note: the actual GTP tunnels are created in the F1AP breanch of
    * ue_context_*_response() */
@@ -140,12 +197,32 @@ static int handle_ue_context_drbs_setup(int rnti,
   AssertFatal(*resp_drbs != NULL, "out of memory\n");
   for (int i = 0; i < drbs_len; i++) {
     const f1ap_drb_to_be_setup_t *drb = &req_drbs[i];
+    f1ap_drb_to_be_setup_t *resp_drb = &(*resp_drbs)[i];
     NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_drb(drb);
     nr_rlc_add_drb(rnti, drb->drb_id, rlc_BearerConfig);
 
-    (*resp_drbs)[i] = *drb;
+    *resp_drb = *drb;
     // just put same number of tunnels in DL as in UL
-    (*resp_drbs)[i].up_dl_tnl_length = drb->up_ul_tnl_length;
+    DevAssert(drb->up_ul_tnl_length == 1);
+    resp_drb->up_dl_tnl_length = drb->up_ul_tnl_length;
+
+    if (f1inst >= 0) { // we actually use F1-U
+      int qfi = -1; // don't put PDU session marker in GTP
+      gtpv1u_gnb_create_tunnel_resp_t resp_f1 = {0};
+      int ret = drb_gtpu_create(f1inst,
+                                rnti,
+                                drb->drb_id,
+                                drb->drb_id,
+                                qfi,
+                                drb->up_ul_tnl[0].tl_address,
+                                drb->up_ul_tnl[0].teid,
+                                DURecvCb,
+                                NULL,
+                                &resp_f1);
+      AssertFatal(ret >= 0, "Unable to create GTP Tunnel for F1-U\n");
+      memcpy(&resp_drb->up_dl_tnl[0].tl_address, &resp_f1.gnb_addr.buffer, 4);
+      resp_drb->up_dl_tnl[0].teid = resp_f1.gnb_NGu_teid[0];
+    }
 
     int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig);
     DevAssert(ret == 0);
@@ -159,6 +236,7 @@ static int handle_ue_context_drbs_release(int rnti,
                                           NR_CellGroupConfig_t *cellGroupConfig)
 {
   DevAssert(req_drbs != NULL && cellGroupConfig != NULL);
+  instance_t f1inst = get_f1_gtp_instance();
 
   cellGroupConfig->rlc_BearerToReleaseList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToReleaseList));
   AssertFatal(cellGroupConfig->rlc_BearerToReleaseList != NULL, "out of memory\n");
@@ -178,6 +256,8 @@ static int handle_ue_context_drbs_release(int rnti,
     }
     if (idx < cellGroupConfig->rlc_BearerToAddModList->list.count) {
       nr_rlc_release_entity(rnti, lcid);
+      if (f1inst >= 0)
+        newGtpuDeleteOneTunnel(f1inst, rnti, drb->rb_id);
       asn_sequence_del(&cellGroupConfig->rlc_BearerToAddModList->list, idx, 1);
       long *plcid = malloc(sizeof(*plcid));
       AssertFatal(plcid != NULL, "out of memory\n");
@@ -557,6 +637,10 @@ void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd)
     return;
   }
 
+  instance_t f1inst = get_f1_gtp_instance();
+  if (f1inst >= 0)
+    newGtpuDeleteAllTunnels(f1inst, cmd->gNB_DU_ue_id);
+
   if (UE->UE_sched_ctrl.ul_failure || cmd->rrc_container_length == 0) {
     /* The UE is already not connected anymore or we have nothing to forward*/
     nr_mac_release_ue(mac, cmd->gNB_DU_ue_id);
@@ -632,6 +716,9 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
     pthread_mutex_unlock(&mac->sched_lock);
     nr_rlc_remove_ue(dl_rrc->gNB_DU_ue_id);
     nr_rlc_update_rnti(*dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id);
+    instance_t f1inst = get_f1_gtp_instance();
+    if (f1inst >= 0) // we actually use F1-U
+      gtpv1u_update_ue_id(f1inst, *dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id);
   }
 
   /* the DU ue id is the RNTI */