diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 8500749fe285827f94987e0bfb4fb084b99a56bd..5abda203f296e356d2e0dfd737872b3c301dfd9c 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -100,9 +100,17 @@ nfapi_ue_release_request_body_t release_rntis;
 //Fixme: Uniq dirty DU instance, by global var, datamodel need better management
 instance_t DUuniqInstance=0;
 instance_t CUuniqInstance=0;
-teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_bearer_id, teid_t outgoing_teid,
-                           transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) {
-return 0;
+teid_t newGtpuCreateTunnel(instance_t instance,
+                           rnti_t rnti,
+                           int incoming_bearer_id,
+                           int outgoing_bearer_id,
+                           teid_t outgoing_teid,
+                           int qfi,
+                           transport_layer_addr_t remoteAddr,
+                           int port,
+                           gtpCallback callBack,
+                           gtpCallbackSDAP callBackSDAP) {
+  return 0;
 }
 
 int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) {
diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c
index 33717c944dcd5e7eff84e679d9dbc456b10e080e..76776ce1101a9a049661bdab78e3885c551f60af 100644
--- a/openair1/SIMULATION/NR_PHY/prachsim.c
+++ b/openair1/SIMULATION/NR_PHY/prachsim.c
@@ -92,9 +92,17 @@ int oai_nfapi_nr_rach_indication(nfapi_nr_rach_indication_t *ind) { return(0);
 //Fixme: Uniq dirty DU instance, by global var, datamodel need better management
 instance_t DUuniqInstance=0;
 instance_t CUuniqInstance=0;
-teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_bearer_id, teid_t outgoing_teid,
-                           transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) {
-return 0;
+teid_t newGtpuCreateTunnel(instance_t instance,
+                           rnti_t rnti,
+                           int incoming_bearer_id,
+                           int outgoing_bearer_id,
+                           teid_t outgoing_teid,
+                           int qfi,
+                           transport_layer_addr_t remoteAddr,
+                           int port,
+                           gtpCallback callBack,
+                           gtpCallbackSDAP callBackSDAP) {
+  return 0;
 }
 
 int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) {
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index ffb168fd68d5b7d2a297fb25797d9be8deb7f46c..5df89283a806550463a776e37aa2cf3832963534 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -95,9 +95,17 @@ nfapi_ue_release_request_body_t release_rntis;
 //Fixme: Uniq dirty DU instance, by global var, datamodel need better management
 instance_t DUuniqInstance=0;
 instance_t CUuniqInstance=0;
-teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_bearer_id, teid_t outgoing_teid,
-                           transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) {
-return 0;
+teid_t newGtpuCreateTunnel(instance_t instance,
+                           rnti_t rnti,
+                           int incoming_bearer_id,
+                           int outgoing_bearer_id,
+                           teid_t outgoing_teid,
+                           int qfi,
+                           transport_layer_addr_t remoteAddr,
+                           int port,
+                           gtpCallback callBack,
+                           gtpCallbackSDAP callBackSDAP) {
+  return 0;
 }
 
 int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) {
diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h
index 4111b00024a0ea22b82323848cbdf141e2b72e1d..7758395ee43fd2274cfbefdf998348c518c4e9f8 100644
--- a/openair2/COMMON/gtpv1_u_messages_types.h
+++ b/openair2/COMMON/gtpv1_u_messages_types.h
@@ -181,6 +181,7 @@ typedef struct gtpv1u_gnb_create_tunnel_req_s {
   int                    num_tunnels;
   //teid_t                 upf_NGu_teid[NR_GTPV1U_MAX_BEARERS_PER_UE];  ///< Tunnel Endpoint Identifier
   teid_t                 outgoing_teid[NR_GTPV1U_MAX_BEARERS_PER_UE];
+  int outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE];
   pdusessionid_t         pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
   ebi_t                  incoming_rb_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
   //ebi_t                  outgoing_rb_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c
index 859a9f5e0df4efc5160cd6500b553c5da2864b17..0f3959d4ad527c20cde7e999eca9da62f5903a59 100644
--- a/openair2/F1AP/f1ap_cu_ue_context_management.c
+++ b/openair2/F1AP/f1ap_cu_ue_context_management.c
@@ -515,15 +515,16 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance,
         int sz=sizeof(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address);
         memcpy(addr.buffer,&f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz);
         addr.length = sz*8;
-        f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid=
-            newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst,
-              f1ap_ue_context_setup_req->rnti,
-              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
-              addr,
-              f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].port,
-              cu_f1u_data_req);
+        f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid = newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst,
+                                                                                               f1ap_ue_context_setup_req->rnti,
+                                                                                               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,
+                                                                                               f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].port,
+                                                                                               cu_f1u_data_req,
+                                                                                               NULL);
         /*  12.3.1 ULTunnels_ToBeSetup_Item */
         asn1cSequenceAdd(drbs_toBeSetup_item->uLUPTNLInformation_ToBeSetup_List.list,
           F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item);
@@ -1491,15 +1492,16 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context
         memcpy(addr.buffer,&f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz);
         addr.length = sz*8;
 
-        f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid=
-            newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst,
-              f1ap_ue_context_modification_req->rnti,
-              f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id,
-              f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id,
-              0xFFFF, // We will set the right value from DU answer
-              addr,
-              f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].port,
-              cu_f1u_data_req);
+        f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid = newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst,
+                                                                                                      f1ap_ue_context_modification_req->rnti,
+                                                                                                      f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id,
+                                                                                                      f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id,
+                                                                                                      0xFFFF, // We will set the right value from DU answer
+                                                                                                      -1, // no qfi
+                                                                                                      addr,
+                                                                                                      f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].port,
+                                                                                                      cu_f1u_data_req,
+                                                                                                      NULL);
         /*  12.3.1 ULTunnels_ToBeSetup_Item */
         asn1cSequenceAdd(drbs_toBeSetupMod_item->uLUPTNLInformation_ToBeSetup_List.list,
                        F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item);
diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c
index 74e0200f09a77fef5580d7dc81efd15e030d529a..cb15862921412be5bfd085cc01ecbcf92121db3e 100644
--- a/openair2/F1AP/f1ap_du_ue_context_management.c
+++ b/openair2/F1AP/f1ap_du_ue_context_management.c
@@ -187,14 +187,16 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t       instance,
         transport_layer_addr_t addr;
         memcpy(addr.buffer, &drb_p->up_ul_tnl[0].tl_address, sizeof(drb_p->up_ul_tnl[0].tl_address));
         addr.length=sizeof(drb_p->up_ul_tnl[0].tl_address)*8;
-        drb_p->up_dl_tnl[0].teid=newGtpuCreateTunnel(INSTANCE_DEFAULT,
-                                 f1ap_ue_context_setup_req->rnti,
-                                 drb_p->drb_id,
-                                 drb_p->drb_id,
-                                 drb_p->up_ul_tnl[0].teid,
-                                 addr,
-                                 drb_p->up_ul_tnl[0].port,
-                                 lteDURecvCb);
+        drb_p->up_dl_tnl[0].teid = newGtpuCreateTunnel(INSTANCE_DEFAULT,
+                                                       f1ap_ue_context_setup_req->rnti,
+                                                       drb_p->drb_id,
+                                                       drb_p->drb_id,
+                                                       drb_p->up_ul_tnl[0].teid,
+                                                       -1, // no qfi
+                                                       addr,
+                                                       drb_p->up_ul_tnl[0].port,
+                                                       lteDURecvCb,
+                                                       NULL);
         drb_p->up_dl_tnl_length++;
       }
     }
@@ -1171,14 +1173,16 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t       instance,
         transport_layer_addr_t addr;
           memcpy(addr.buffer, &drb_p->up_ul_tnl[0].tl_address, sizeof(drb_p->up_ul_tnl[0].tl_address));
           addr.length=sizeof(drb_p->up_ul_tnl[0].tl_address)*8;
-          drb_p->up_dl_tnl[0].teid=newGtpuCreateTunnel(INSTANCE_DEFAULT,
-                               f1ap_ue_context_modification_req->rnti,
-                               drb_p->drb_id,
-                               drb_p->drb_id,
-                               drb_p->up_ul_tnl[0].teid,
-                               addr,
-                               drb_p->up_ul_tnl[0].port,
-                               lteDURecvCb);
+          drb_p->up_dl_tnl[0].teid = newGtpuCreateTunnel(INSTANCE_DEFAULT,
+                                                         f1ap_ue_context_modification_req->rnti,
+                                                         drb_p->drb_id,
+                                                         drb_p->drb_id,
+                                                         drb_p->up_ul_tnl[0].teid,
+                                                         -1, // no qfi
+                                                         addr,
+                                                         drb_p->up_ul_tnl[0].port,
+                                                         lteDURecvCb,
+                                                         NULL);
           drb_p->up_dl_tnl_length++;
       }
     }
diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c
index 648df1a306c71b2db32ea349bd6eb484778ca324..8c6c583289a2448a95c49e98ab18de8028cde3fc 100755
--- a/openair2/RRC/NR/rrc_gNB.c
+++ b/openair2/RRC/NR/rrc_gNB.c
@@ -1767,15 +1767,16 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete(
       }
     }
 
-    gtpv1u_gnb_create_tunnel_req_t  create_tunnel_req;
+    gtpv1u_gnb_create_tunnel_req_t  create_tunnel_req={0};
     /* Save e RAB information for later */
-    memset(&create_tunnel_req, 0, sizeof(create_tunnel_req));
 
     for ( j = 0, i = 0; i < NB_RB_MAX; i++) {
       if (ue_context_pP->ue_context.pduSession[i].status == PDU_SESSION_STATUS_ESTABLISHED || ue_context_pP->ue_context.pduSession[i].status == PDU_SESSION_STATUS_DONE) {
         create_tunnel_req.pdusession_id[j]   = ue_context_pP->ue_context.pduSession[i].param.pdusession_id;
         create_tunnel_req.incoming_rb_id[j]  = i+1;
         create_tunnel_req.outgoing_teid[j]  = ue_context_pP->ue_context.pduSession[i].param.gtp_teid;
+        // to be developped, use the first QFI only
+        create_tunnel_req.outgoing_qfi[j]  = ue_context_pP->ue_context.pduSession[i].param.qos[0].qfi;
         memcpy(create_tunnel_req.dst_addr[j].buffer,
                ue_context_pP->ue_context.pduSession[i].param.upf_addr.buffer,
                 sizeof(uint8_t)*20);
@@ -2805,8 +2806,6 @@ rrc_gNB_decode_dcch(
           SRBs[0].lcid = 2;
 
           /*Instruction towards the DU for DRB configuration and tunnel creation*/
-          gtpv1u_gnb_create_tunnel_req_t  create_tunnel_req;
-          memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t));
           req->drbs_to_be_setup = malloc(1*sizeof(f1ap_drb_to_be_setup_t));
           req->drbs_to_be_setup_length = 1;
           f1ap_drb_to_be_setup_t *DRBs=req->drbs_to_be_setup;
@@ -3433,14 +3432,16 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha
       addr.length=sizeof(drb_p.up_ul_tnl[0].tl_address)*8;
       extern instance_t DUuniqInstance;
       if (!drb_id_to_setup_start) drb_id_to_setup_start = drb_p.drb_id;
-      incoming_teid=newGtpuCreateTunnel(DUuniqInstance,
-          req->rnti,
-          drb_p.drb_id,
-          drb_p.drb_id,
-          drb_p.up_ul_tnl[0].teid,
-          addr,
-          drb_p.up_ul_tnl[0].port,
-          DURecvCb);
+      incoming_teid = newGtpuCreateTunnel(DUuniqInstance,
+                                          req->rnti,
+                                          drb_p.drb_id,
+                                          drb_p.drb_id,
+                                          drb_p.up_ul_tnl[0].teid,
+                                          -1, // no qfi
+                                          addr,
+                                          drb_p.up_ul_tnl[0].port,
+                                          DURecvCb,
+                                          NULL);
     }
   }
 
@@ -3572,14 +3573,16 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co
       memcpy(addr.buffer, &drb_p.up_ul_tnl[0].tl_address, sizeof(drb_p.up_ul_tnl[0].tl_address));
       addr.length=sizeof(drb_p.up_ul_tnl[0].tl_address)*8;
       extern instance_t DUuniqInstance;
-      incoming_teid=newGtpuCreateTunnel(DUuniqInstance,
-          req->rnti,
-          drb_p.drb_id,
-          drb_p.drb_id,
-          drb_p.up_ul_tnl[0].teid,
-          addr,
-          drb_p.up_ul_tnl[0].port,
-          DURecvCb);
+      incoming_teid = newGtpuCreateTunnel(DUuniqInstance,
+                                          req->rnti,
+                                          drb_p.drb_id,
+                                          drb_p.drb_id,
+                                          drb_p.up_ul_tnl[0].teid,
+                                          -1, // no qfi
+                                          addr,
+                                          drb_p.up_ul_tnl[0].port,
+                                          DURecvCb,
+                                          NULL);
     }
   }
 
diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c
index 6663ddea8575d349a80e80f10f87c8f815657e53..8e1975ea1195f8e7b603a6278fb8ff573e8d09d8 100644
--- a/openair2/RRC/NR/rrc_gNB_NGAP.c
+++ b/openair2/RRC/NR/rrc_gNB_NGAP.c
@@ -474,7 +474,6 @@ rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(
     rrc_gNB_ue_context_t            *ue_context_p = NULL;
     protocol_ctxt_t                 ctxt={0};
     uint8_t                         pdu_sessions_done = 0;
-    gtpv1u_gnb_create_tunnel_req_t  create_tunnel_req;
     gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp;
     uint8_t                         inde_list[NR_NB_RB_MAX - 3]= {0};
     int                             ret = 0;
@@ -503,7 +502,7 @@ rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(
 
       uint8_t nb_pdusessions_tosetup = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).nb_of_pdusessions;
       if (nb_pdusessions_tosetup != 0) {
-        memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t));
+        gtpv1u_gnb_create_tunnel_req_t  create_tunnel_req={0};
         for (int i = 0; i < NR_NB_RB_MAX - 3; i++) {
           if(ue_context_p->ue_context.pduSession[i].status >= PDU_SESSION_STATUS_DONE)
             continue;
@@ -512,6 +511,8 @@ rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(
           create_tunnel_req.pdusession_id[pdu_sessions_done]   = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].pdusession_id;
           create_tunnel_req.incoming_rb_id[pdu_sessions_done]  = i+1;
           create_tunnel_req.outgoing_teid[pdu_sessions_done]    = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].gtp_teid;
+          // To be developped: hardcoded first flow 
+          create_tunnel_req.outgoing_qfi[pdu_sessions_done]    = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].qos[0].qfi;
           create_tunnel_req.dst_addr[pdu_sessions_done].length = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].upf_addr.length;
           memcpy(create_tunnel_req.dst_addr[pdu_sessions_done].buffer,
                   NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].upf_addr.buffer,
@@ -1003,6 +1004,7 @@ rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(
       create_tunnel_req.pdusession_id[pdu_sessions_done] = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].pdusession_id;
       create_tunnel_req.incoming_rb_id[pdu_sessions_done]= i+1;
       create_tunnel_req.outgoing_teid[pdu_sessions_done]  = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].gtp_teid;
+      create_tunnel_req.outgoing_qfi[pdu_sessions_done]  = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].qos[0].qfi;
       memcpy(create_tunnel_req.dst_addr[pdu_sessions_done].buffer,
               NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].upf_addr.buffer,
               sizeof(uint8_t)*20);
diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp
index 3626e0b8eddfd6221b0bfef39f3c7be47c5a3b41..e318f0cf95c317e46119fd25a18f3eeff8c54bec 100644
--- a/openair3/ocp-gtpu/gtp_itf.cpp
+++ b/openair3/ocp-gtpu/gtp_itf.cpp
@@ -21,8 +21,6 @@ extern "C" {
 #include "openair2/SDAP/nr_sdap/nr_sdap.h"
 //#include <openair1/PHY/phy_extern.h>
 
-static bool is_gnb = false;
-
 #pragma pack(1)
 
 typedef struct Gtpv1uMsgHeader {
@@ -60,18 +58,21 @@ typedef struct Gtpv1uMsgHeaderOptFields {
   uint8_t NextExtHeaderType;    
 } __attribute__((packed)) Gtpv1uMsgHeaderOptFieldsT;
 
-typedef struct PDUSessionContainer {
+#define DL_PDU_SESSION_INFORMATION 0
+#define UL_PDU_SESSION_INFORMATION 1
+
+  typedef struct PDUSessionContainer {
   uint8_t spare:4;
   uint8_t PDU_type:4;
   uint8_t QFI:6;
-  uint8_t RQI:1;
-  uint8_t PPP:1;
+  uint8_t Reflective_QoS_activation:1;
+  uint8_t Paging_Policy_Indicator:1;
 } __attribute__((packed)) PDUSessionContainerT;
 
 typedef struct Gtpv1uExtHeader {
   uint8_t ExtHeaderLen;
   PDUSessionContainerT pdusession_cntr;
-  //uint8_t NextExtHeaderType;
+  uint8_t NextExtHeaderType;
 }__attribute__((packed)) Gtpv1uExtHeaderT;
 
 #pragma pack()
@@ -103,6 +104,7 @@ typedef struct gtpv1u_bearer_s {
   tcp_udp_port_t  outgoing_port;
   uint16_t        seqNum;
   uint8_t         npduNum;
+  int outgoing_qfi;
 } gtpv1u_bearer_t;
 
 typedef struct {
@@ -159,75 +161,80 @@ instance_t legacyInstanceMapping=0;
 
 #define GTPV1U_HEADER_SIZE                                  (8)
   
-  
-  static int gtpv1uCreateAndSendMsg(int h, uint32_t peerIp, uint16_t peerPort, int msgType, teid_t teid, uint8_t *Msg,int msgLen,
-                                   bool seqNumFlag, bool  npduNumFlag, bool extHdrFlag, int seqNum, int npduNum, int extHdrType,
-                                   uint8_t *extensionHeader_buffer, uint8_t extensionHeader_length) {
+  #define HDR_MAX 256 // 256 is supposed to be larger than any gtp header
+static int gtpv1uCreateAndSendMsg(int h,
+                                  uint32_t peerIp,
+                                  uint16_t peerPort,
+                                  int msgType,
+                                  teid_t teid,
+                                  uint8_t *Msg,
+                                  int msgLen,
+                                  bool seqNumFlag,
+                                  bool npduNumFlag,
+                                  int seqNum,
+                                  int npduNum,
+                                  int extHdrType,
+                                  uint8_t *extensionHeader_buffer,
+                                  uint8_t extensionHeader_length) {
   LOG_D(GTPU, "Peer IP:%u peer port:%u outgoing teid:%u \n", peerIp, peerPort, teid);
-  int headerAdditional=0;
 
-  if ( seqNumFlag || npduNumFlag || extHdrFlag)
-    headerAdditional=4;
-
-  int fullSize=GTPV1U_HEADER_SIZE+headerAdditional+msgLen+extensionHeader_length;
-  uint8_t buffer[fullSize];
+  uint8_t buffer[msgLen+HDR_MAX]; 
+  uint8_t *curPtr=buffer;
   Gtpv1uMsgHeaderT      *msgHdr = (Gtpv1uMsgHeaderT *)buffer ;
   // N should be 0 for us (it was used only in 2G and 3G)
   msgHdr->PN=npduNumFlag;
   msgHdr->S=seqNumFlag;
-  msgHdr->E=extHdrFlag;
+  msgHdr->E = extHdrType;
   msgHdr->spare=0;
   //PT=0 is for GTP' TS 32.295 (charging)
   msgHdr->PT=1;
   msgHdr->version=1;
   msgHdr->msgType=msgType;
-  msgHdr->msgLength=htons(msgLen+extensionHeader_length);
-
-  if ( seqNumFlag || extHdrFlag || npduNumFlag)
-    msgHdr->msgLength+=htons(4);
-
+  msgHdr->msgLength = htons(msgLen + extensionHeader_length);
   msgHdr->teid=htonl(teid);
 
-  if(seqNumFlag || extHdrFlag || npduNumFlag) {
-    *((uint16_t *) (buffer+8)) = seqNumFlag ? seqNum : 0x0000;
-    *((uint8_t *) (buffer+10)) = npduNumFlag ? npduNum : 0x00;
-    *((uint8_t *) (buffer+11)) = extHdrFlag ? extHdrType : 0x00;
+  curPtr+=sizeof(Gtpv1uMsgHeaderT);
 
-    /**(buffer+8) = seqNumFlag ? htons(seqNum) : 0x0000;
-    *(buffer+10) = npduNumFlag ? htons(npduNum) : 0x00;
-    *(buffer+11) = extHdrFlag ? htons(extHdrType) : 0x00;
-    *(buffer+11) = extHdrType;*/
+  if (seqNumFlag || (extHdrType != NO_MORE_EXT_HDRS) || npduNumFlag) {
+    msgHdr->msgLength += htons(4);
+    *(uint16_t *)curPtr = seqNumFlag ? seqNum : 0x0000;
+    curPtr+=sizeof(uint16_t);
+    *(uint8_t *)curPtr = npduNumFlag ? npduNum : 0x00;
+    curPtr++;
+    *(uint8_t *)curPtr = extHdrType;
+    curPtr++;
   }
 
-  if(extHdrFlag){
-    while (extHdrType){
-      if (extensionHeader_length > 0 && extHdrType == 0x84){
-        memcpy(buffer+GTPV1U_HEADER_SIZE+headerAdditional, extensionHeader_buffer, extensionHeader_length);
-        LOG_D(GTPU, "Extension Header for DDD added. The length is: %d, extension header type is: %x \n", extensionHeader_length, *((uint8_t *) (buffer+11))); 
-        extHdrType = extensionHeader_buffer[extensionHeader_length -1];
-        LOG_D(GTPU, "Next extension header type is: %x \n", *((uint8_t *) (buffer+11)));
-      }
-      else {
-        LOG_W(GTPU, "Extension header type not supported, returning... \n");
-        return GTPNOK;
-      }
+  // Bug: if there is more than one extension, infinite loop on extensionHeader_buffer
+  while (extHdrType != NO_MORE_EXT_HDRS) {
+    if (extensionHeader_length > 0) {
+      memcpy(curPtr, extensionHeader_buffer, extensionHeader_length);
+      curPtr += extensionHeader_length;
+      LOG_D(GTPU, "Extension Header for DDD added. The length is: %d, extension header type is: %x \n", extensionHeader_length, *((uint8_t *)(buffer + 11)));
+      extHdrType = extensionHeader_buffer[extensionHeader_length - 1];
+      LOG_D(GTPU, "Next extension header type is: %x \n", *((uint8_t *)(buffer + 11)));
+    } else {
+      LOG_W(GTPU, "Extension header type not supported, returning... \n");
     }
   }
+
   if (Msg!= NULL){
-    memcpy(buffer+GTPV1U_HEADER_SIZE+headerAdditional+extensionHeader_length, Msg, msgLen);
+    memcpy(curPtr, Msg, msgLen);
+    curPtr+=msgLen;
   }
 
+  AssertFatal(curPtr-(buffer+msgLen) < HDR_MAX, "");
   // Fix me: add IPv6 support, using flag ipVersion
   static struct sockaddr_in to= {0};
   to.sin_family      = AF_INET;
   to.sin_port        = htons(peerPort);
   to.sin_addr.s_addr = peerIp ;
-  LOG_D(GTPU,"sending packet size: %d to %s\n",fullSize, inet_ntoa(to.sin_addr) );
+  LOG_D(GTPU,"sending packet size: %ld to %s\n",curPtr-buffer, inet_ntoa(to.sin_addr) );
   int ret;
 
-  if ((ret=sendto(h, (void *)buffer, (size_t)fullSize, 0,(struct sockaddr *)&to, sizeof(to) )) != fullSize ) {
-    LOG_E(GTPU, "[SD %d] Failed to send data to " IPV4_ADDR " on port %d, buffer size %u, ret: %d, errno: %d\n",
-          h, IPV4_ADDR_FORMAT(peerIp), peerPort, fullSize, ret, errno);
+  if ((ret=sendto(h, (void *)buffer, curPtr-buffer, 0,(struct sockaddr *)&to, sizeof(to) )) != curPtr-buffer ) {
+    LOG_E(GTPU, "[SD %d] Failed to send data to " IPV4_ADDR " on port %d, buffer size %lu, ret: %d, errno: %d\n",
+          h, IPV4_ADDR_FORMAT(peerIp), peerPort, curPtr-buffer, ret, errno);
     return GTPNOK;
   }
 
@@ -269,12 +276,8 @@ static void gtpv1uSend(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req, b
   // copy to release the mutex
   gtpv1u_bearer_t tmp=ptr2->second;
   pthread_mutex_unlock(&globGtp.gtp_lock);
-  gtpv1uCreateAndSendMsg(compatInst(instance),
-                         tmp.outgoing_ip_addr,
-                         tmp.outgoing_port,
-                         GTP_GPDU,
-                         tmp.teid_outgoing,
-                         buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0, NULL, 0) ;
+  gtpv1uCreateAndSendMsg(
+      compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, buffer, length, seqNumFlag, npduNumFlag, tmp.seqNum, tmp.npduNum, NO_MORE_EXT_HDRS, NULL, 0);
 }
 
 static void gtpv1uSend2(instance_t instance, gtpv1u_gnb_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) {
@@ -312,12 +315,35 @@ static void gtpv1uSend2(instance_t instance, gtpv1u_gnb_tunnel_data_req_t *req,
   // copy to release the mutex
   gtpv1u_bearer_t tmp=ptr2->second;
   pthread_mutex_unlock(&globGtp.gtp_lock);
-  gtpv1uCreateAndSendMsg(compatInst(instance),
-                         tmp.outgoing_ip_addr,
-                         tmp.outgoing_port,
-                         GTP_GPDU,
-                         tmp.teid_outgoing,
-                         buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0, NULL, 0) ;
+
+  if (tmp.outgoing_qfi != -1) {
+    Gtpv1uExtHeaderT ext = { 0 };
+    ext.ExtHeaderLen = 1; // in quad bytes  EXT_HDR_LNTH_OCTET_UNITS
+    ext.pdusession_cntr.spare = 0;
+    ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION;
+    ext.pdusession_cntr.QFI = tmp.outgoing_qfi;
+    ext.pdusession_cntr.Reflective_QoS_activation = false;
+    ext.pdusession_cntr.Paging_Policy_Indicator = false;
+    ext.NextExtHeaderType = NO_MORE_EXT_HDRS;
+
+    gtpv1uCreateAndSendMsg(compatInst(instance),
+                           tmp.outgoing_ip_addr,
+                           tmp.outgoing_port,
+                           GTP_GPDU,
+                           tmp.teid_outgoing,
+                           buffer,
+                           length,
+                           seqNumFlag,
+                           npduNumFlag,
+                           tmp.seqNum,
+                           tmp.npduNum,
+                           PDU_SESSION_CONTAINER,
+                           (uint8_t *)&ext,
+                           sizeof(ext));
+  } else {
+    gtpv1uCreateAndSendMsg(
+        compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, buffer, length, seqNumFlag, npduNumFlag, tmp.seqNum, tmp.npduNum, NO_MORE_EXT_HDRS, NULL, 0);
+  }
 }
 
 static void fillDlDeliveryStatusReport(extensionHeader_t *extensionHeader, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN){
@@ -379,13 +405,8 @@ static void gtpv1uSendDlDeliveryStatus(instance_t instance, gtpv1u_DU_buffer_rep
   // copy to release the mutex
   gtpv1u_bearer_t tmp=ptr2->second;
   pthread_mutex_unlock(&globGtp.gtp_lock);
-  gtpv1uCreateAndSendMsg(compatInst(instance),
-      tmp.outgoing_ip_addr,
-      tmp.outgoing_port,
-      GTP_GPDU,
-      tmp.teid_outgoing,
-      NULL, 0, false, false, true, 0, 0, 0x84, extensionHeader->buffer, extensionHeader->length) ;
-
+  gtpv1uCreateAndSendMsg(
+      compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER, extensionHeader->buffer, extensionHeader->length);
 }
 
 static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req) {
@@ -567,8 +588,16 @@ void GtpuUpdateTunnelOutgoingTeid(instance_t instance, rnti_t rnti, ebi_t bearer
   return;
 }
 
-teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_bearer_id, teid_t outgoing_teid,
-                           transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) {
+teid_t newGtpuCreateTunnel(instance_t instance,
+                           rnti_t rnti,
+                           int incoming_bearer_id,
+                           int outgoing_bearer_id,
+                           teid_t outgoing_teid,
+                           int outgoing_qfi,
+                           transport_layer_addr_t remoteAddr,
+                           int port,
+                           gtpCallback callBack,
+                           gtpCallbackSDAP callBackSDAP) {
   pthread_mutex_lock(&globGtp.gtp_lock);
   instance=compatInst(instance);
   auto inst=&globGtp.instances[instance];
@@ -593,8 +622,8 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer
   inst->te2ue_mapping[incoming_teid].outgoing_teid= outgoing_teid;
 
   inst->te2ue_mapping[incoming_teid].callBack=callBack;
-  
-  inst->te2ue_mapping[incoming_teid].callBackSDAP = sdap_data_req;
+
+  inst->te2ue_mapping[incoming_teid].callBackSDAP = callBackSDAP;
 
   inst->te2ue_mapping[incoming_teid].pdusession_id = (uint8_t)outgoing_bearer_id;
 
@@ -625,6 +654,7 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer
   tmp->teid_incoming = incoming_teid;
   tmp->outgoing_port=port;
   tmp->teid_outgoing= outgoing_teid;
+  tmp->outgoing_qfi=outgoing_qfi;
   pthread_mutex_unlock(&globGtp.gtp_lock);
   char ip4[INET_ADDRSTRLEN];
   char ip6[INET6_ADDRSTRLEN];
@@ -653,12 +683,16 @@ int gtpv1u_create_s1u_tunnel(instance_t instance,
                 "From legacy code not clear, seems impossible (bearer=%d)\n",
                 create_tunnel_req->eps_bearer_id[i]);
     int incoming_rb_id=create_tunnel_req->eps_bearer_id[i]-4;
-    teid_t teid=newGtpuCreateTunnel(compatInst(instance), create_tunnel_req->rnti,
-                                    incoming_rb_id,
-                                    create_tunnel_req->eps_bearer_id[i],
-                                    create_tunnel_req->sgw_S1u_teid[i],
-                                    create_tunnel_req->sgw_addr[i],  dstport,
-                                    pdcp_data_req);
+    teid_t teid = newGtpuCreateTunnel(compatInst(instance),
+                                      create_tunnel_req->rnti,
+                                      incoming_rb_id,
+                                      create_tunnel_req->eps_bearer_id[i],
+                                      create_tunnel_req->sgw_S1u_teid[i],
+                                      -1, // no pdu session in 4G
+                                      create_tunnel_req->sgw_addr[i],
+                                      dstport,
+                                      pdcp_data_req,
+                                      NULL);
     create_tunnel_resp->status=0;
     create_tunnel_resp->rnti=create_tunnel_req->rnti;
     create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels;
@@ -715,15 +749,18 @@ int gtpv1u_create_ngu_tunnel(  const instance_t instance,
         create_tunnel_req->rnti,
         create_tunnel_req->num_tunnels,
         create_tunnel_req->outgoing_teid[0]);
-  tcp_udp_port_t dstport=globGtp.instances[compatInst(instance)].get_dstport();
-  is_gnb = true;
+  tcp_udp_port_t dstport = globGtp.instances[compatInst(instance)].get_dstport();
   for (int i = 0; i < create_tunnel_req->num_tunnels; i++) {
-    teid_t teid=newGtpuCreateTunnel(instance, create_tunnel_req->rnti,
-                                    create_tunnel_req->incoming_rb_id[i],
-                                    create_tunnel_req->pdusession_id[i],
-                                    create_tunnel_req->outgoing_teid[i],
-                                    create_tunnel_req->dst_addr[i], dstport,
-                                    pdcp_data_req);
+    teid_t teid = newGtpuCreateTunnel(instance,
+                                      create_tunnel_req->rnti,
+                                      create_tunnel_req->incoming_rb_id[i],
+                                      create_tunnel_req->pdusession_id[i],
+                                      create_tunnel_req->outgoing_teid[i],
+                                      create_tunnel_req->outgoing_qfi[i],
+                                      create_tunnel_req->dst_addr[i],
+                                      dstport,
+                                      pdcp_data_req,
+                                      sdap_data_req);
     create_tunnel_resp->status=0;
     create_tunnel_resp->rnti=create_tunnel_req->rnti;
     create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels;
@@ -853,9 +890,7 @@ static int Gtpv1uHandleEchoReq(int h,
   uint16_t seq=ntohs(*(uint16_t *)(msgHdr+1));
   LOG_D(GTPU, "[%d] Received a echo request, TEID: %d, seq: %hu\n", h, msgHdr->teid, seq);
   uint8_t recovery[2]= {14,0};
-  return gtpv1uCreateAndSendMsg(h, peerIp, peerPort, GTP_ECHO_RSP, ntohl(msgHdr->teid),
-			 recovery, sizeof recovery,
-			 1, 0, 0, seq, 0, 0, NULL, 0);
+  return gtpv1uCreateAndSendMsg(h, peerIp, peerPort, GTP_ECHO_RSP, ntohl(msgHdr->teid), recovery, sizeof recovery, true, false, seq, 0, NO_MORE_EXT_HDRS, NULL, 0);
 }
 
 static int Gtpv1uHandleError(int h,
@@ -968,7 +1003,7 @@ static int Gtpv1uHandleGpdu(int h,
   //Minimum length of GTP-U header if non of the optional fields are present
   int offset = sizeof(Gtpv1uMsgHeaderT);
 
-  uint8_t qfi = 0;
+  uint8_t qfi = -1;
   bool rqi = false;
   uint32_t NR_PDCP_PDU_SN = 0;
 
@@ -986,7 +1021,7 @@ static int Gtpv1uHandleGpdu(int h,
         case PDU_SESSION_CONTAINER: {
           PDUSessionContainerT *pdusession_cntr = (PDUSessionContainerT *)(msgBuf + offset + 1);
           qfi = pdusession_cntr->QFI;
-          rqi = pdusession_cntr->RQI;
+          rqi = pdusession_cntr->Reflective_QoS_activation;
           break;
         }
         case NR_RAN_CONTAINER: {
@@ -1047,7 +1082,7 @@ static int Gtpv1uHandleGpdu(int h,
   const uint32_t destinationL2Id=0;
   pthread_mutex_unlock(&globGtp.gtp_lock);
 
-  if(is_gnb && qfi){
+  if (qfi != -1 && tunnel->second.callBackSDAP) {
     if ( !tunnel->second.callBackSDAP(&ctxt,
                                       srb_flag,
                                       rb_id,
@@ -1106,12 +1141,8 @@ static int Gtpv1uHandleGpdu(int h,
      * 1 octet for padding + 1 octet for next extension header type,
      * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/
     extensionHeader->length  = 1+sizeof(DlDataDeliveryStatus_flagsT)+3+1+1;
-    gtpv1uCreateAndSendMsg(h,
-        peerIp,
-        peerPort,
-        GTP_GPDU,
-        inst->te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid,
-        NULL, 0, false, false, true, 0, 0, 0x84, extensionHeader->buffer, extensionHeader->length) ;
+    gtpv1uCreateAndSendMsg(
+        h, peerIp, peerPort, GTP_GPDU, inst->te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid, NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER, extensionHeader->buffer, extensionHeader->length);
   }
 
   LOG_D(GTPU,"[%d] Received a %d bytes packet for: teid:%x\n", h,
diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h
index 51a47e8c827c8ea633ce562805abc6afe3caeb18..7951c4db09b8854e55c5c11213d44fc300d9db3c 100644
--- a/openair3/ocp-gtpu/gtp_itf.h
+++ b/openair3/ocp-gtpu/gtp_itf.h
@@ -66,8 +66,16 @@ int gtpv1u_create_x2u_tunnel(
 
 
 // New API
-teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_rb_id, teid_t teid,
-                           transport_layer_addr_t remoteAddr, int port, gtpCallback callBack);
+teid_t newGtpuCreateTunnel(instance_t instance,
+                           rnti_t rnti,
+                           int incoming_bearer_id,
+                           int outgoing_rb_id,
+                           teid_t teid,
+                           int outgoing_qfi,
+                           transport_layer_addr_t remoteAddr,
+                           int port,
+                           gtpCallback callBack,
+                           gtpCallbackSDAP callBackSDAP);
 void GtpuUpdateTunnelOutgoingTeid(instance_t instance, rnti_t rnti, ebi_t bearer_id, teid_t newOutgoingTeid);
 int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti);
 int newGtpuDeleteTunnels(instance_t instance, rnti_t rnti, int nbTunnels, pdusessionid_t *pdusession_id);