From a826af5839cfd8e40b77702bb22019e3ee77b412 Mon Sep 17 00:00:00 2001
From: athanassopoulos <angelo.athanassopoulos@hhi.fraunhofer.de>
Date: Thu, 13 Jan 2022 21:54:26 +0100
Subject: [PATCH] SDAP Initial Implementation

---
 cmake_targets/CMakeLists.txt                 |   3 +-
 common/utils/LOG/log.c                       |   1 +
 common/utils/LOG/log.h                       |   1 +
 common/utils/T/T_messages.txt                |  21 +
 doc/FEATURE_SET.md                           |  16 +
 openair2/COMMON/platform_types.h             |   9 +
 openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c     |   4 +-
 openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h     |   2 +-
 openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c    |  96 ++--
 openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h    |   3 +
 openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c |   4 +-
 openair2/RRC/NR/rrc_gNB.c                    |   8 +-
 openair2/SDAP/nr_sdap/nr_sdap.c              |  73 +++
 openair2/SDAP/nr_sdap/nr_sdap.h              |  59 +++
 openair2/SDAP/nr_sdap/nr_sdap_entity.c       | 474 +++++++++++++++++++
 openair2/SDAP/nr_sdap/nr_sdap_entity.h       | 167 +++++++
 openair2/SDAP/nr_sdap/nr_sdap_gnb.c          |  87 ----
 openair2/SDAP/nr_sdap/nr_sdap_gnb.h          |  61 ---
 openair2/SDAP/nr_sdap/sdap_gNB.c             |  30 --
 openair3/ocp-gtpu/gtp_itf.cpp                |  63 ++-
 20 files changed, 938 insertions(+), 244 deletions(-)
 create mode 100644 openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h
 create mode 100644 openair2/SDAP/nr_sdap/nr_sdap.c
 create mode 100644 openair2/SDAP/nr_sdap/nr_sdap.h
 create mode 100644 openair2/SDAP/nr_sdap/nr_sdap_entity.c
 create mode 100644 openair2/SDAP/nr_sdap/nr_sdap_entity.h
 delete mode 100644 openair2/SDAP/nr_sdap/nr_sdap_gnb.c
 delete mode 100644 openair2/SDAP/nr_sdap/nr_sdap_gnb.h
 delete mode 100644 openair2/SDAP/nr_sdap/sdap_gNB.c

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 46e33e88033..06ba14965c4 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1779,7 +1779,8 @@ set(NR_PDCP_SRC
   )
 
 set(NR_SDAP_SRC
-  ${OPENAIR2_DIR}/SDAP/nr_sdap/nr_sdap_gnb.c
+  ${OPENAIR2_DIR}/SDAP/nr_sdap/nr_sdap.c
+  ${OPENAIR2_DIR}/SDAP/nr_sdap/nr_sdap_entity.c
   )
   
 set(L2_SRC
diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c
index 5b047c082d0..8be35680342 100644
--- a/common/utils/LOG/log.c
+++ b/common/utils/LOG/log.c
@@ -478,6 +478,7 @@ int logInit (void)
   register_log_component("NAS","log",NAS);
   register_log_component("UDP","",UDP_);
   register_log_component("GTPU","",GTPU);
+  register_log_component("SDAP","",SDAP);
   register_log_component("S1AP","",S1AP);
   register_log_component("F1AP","",F1AP);
   register_log_component("M2AP","",M2AP);
diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h
index 1fbf42f62d4..89b9c5e94d2 100644
--- a/common/utils/LOG/log.h
+++ b/common/utils/LOG/log.h
@@ -215,6 +215,7 @@ typedef enum {
   OCM,
   UDP_,
   GTPU,
+  SDAP,
   SPGW,
   S1AP,
   F1AP,
diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt
index a8b919e5252..b3c06d6be8a 100644
--- a/common/utils/T/T_messages.txt
+++ b/common/utils/T/T_messages.txt
@@ -944,6 +944,27 @@ ID = LEGACY_GTPU_TRACE
     GROUP = ALL:LEGACY_GTPU:LEGACY_GROUP_TRACE:LEGACY
     FORMAT = string,log
 
+ID = LEGACY_SDAP_INFO
+    DESC = SDAP legacy logs - info level
+    GROUP = ALL:LEGACY_SDAP:LEGACY_GROUP_INFO:LEGACY
+    FORMAT = string,log
+ID = LEGACY_SDAP_ERROR
+    DESC = SDAP legacy logs - error level
+    GROUP = ALL:LEGACY_SDAP:LEGACY_GROUP_ERROR:LEGACY
+    FORMAT = string,log
+ID = LEGACY_SDAP_WARNING
+    DESC = SDAP legacy logs - warning level
+    GROUP = ALL:LEGACY_SDAP:LEGACY_GROUP_WARNING:LEGACY
+    FORMAT = string,log
+ID = LEGACY_SDAP_DEBUG
+    DESC = SDAP legacy logs - debug level
+    GROUP = ALL:LEGACY_SDAP:LEGACY_GROUP_DEBUG:LEGACY
+    FORMAT = string,log
+ID = LEGACY_SDAP_TRACE
+    DESC = SDAP legacy logs - trace level
+    GROUP = ALL:LEGACY_SDAP:LEGACY_GROUP_TRACE:LEGACY
+    FORMAT = string,log
+
 ID = LEGACY_TMR_INFO
     DESC = TMR legacy logs - info level
     GROUP = ALL:LEGACY_TMR:LEGACY_GROUP_INFO:LEGACY
diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md
index eaa691d6ef0..a289c6d17eb 100644
--- a/doc/FEATURE_SET.md
+++ b/doc/FEATURE_SET.md
@@ -351,6 +351,14 @@ The following features are valid for the gNB and the 5G-NR UE.
   - Interfaces with RRC, RLC 
   - Interfaces with gtp-u (data Tx/Rx over N3 and F1-U interfaces)
 
+**gNB SDAP**
+- Send/Receive operations according to 37.324 Rel.15
+  - Establishment/Handling of SDAP entities.
+  - Transfer of User Plane Data
+  - Mapping between a QoS flow and a DRB for both DL and UL
+  - Marking QoS flow ID in both DL and UL packets
+  - Reflective QoS flow to DRB mapping for UL SDAP data PDUs
+
 **gNB RRC**
 - NR RRC (38.331) Rel 16 messages using new asn1c 
 - LTE RRC (36.331) also updated to Rel 15 
@@ -400,6 +408,7 @@ The following features are valid for the gNB and the 5G-NR UE.
 - New gtp-u implementation supporting both N3 and F1-U interfaces according to 29.281 Rel.15
   - Interfaces with RRC, F1AP for tunnel creation
   - Interfaces with PDCP and RLC for data send/receive at the CU and DU respectively (F1-U interface)
+  - Interface with SDAP for data send/receive, capture of GTP-U Optional Header, GTP-U Extension Header and PDU Session Container.
 
 # OpenAirInterface 5G-NR UE Feature Set #
 
@@ -502,6 +511,13 @@ The following features are valid for the gNB and the 5G-NR UE.
    - Radio bearer establishment/handling and association with PDCP entities
    - Interfaces with RRC, RLC 
 
+**UE SDAP**
+*  Tx/Rx operations operations according to 37.324 Rel.15
+  - Establishment/Handling of SDAP entities.
+  - Transfer of User Plane Data
+  - Reflective Mapping
+  - RRC Signaling Mapping
+
 **UE RRC**
 * Integration of RRC messages and procedures supporting UE 5G SA connection according to 38.331 Rel.16 
    - RRCSetupRequest/RRCSetup/RRCSetupComplete
diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h
index c24291de645..b9a7375b9f2 100644
--- a/openair2/COMMON/platform_types.h
+++ b/openair2/COMMON/platform_types.h
@@ -233,11 +233,20 @@ typedef uint8_t            pdusessionid_t;
 //-----------------------------------------------------------------------------
 // may be ITTI not enabled, but type instance is useful also for OTG,
 typedef intptr_t instance_t;
+
+typedef struct sdap_protocol_ctxt_s {
+  boolean_t   rqi;
+  uint8_t     qfi;
+  boolean_t   dc;
+  int         pdusession_id;
+} sdap_protocol_ctxt_t;
+
 typedef struct protocol_ctxt_s {
   module_id_t module_id;     /*!< \brief  Virtualized module identifier      */
   eNB_flag_t  enb_flag;      /*!< \brief  Flag to indicate eNB (1) or UE (0) */
   instance_t  instance;      /*!< \brief  ITTI or OTG module identifier      */
   rnti_t      rnti;
+  sdap_protocol_ctxt_t sdap;
   frame_t     frame;         /*!< \brief  LTE frame number.*/
   sub_frame_t subframe;      /*!< \brief  LTE sub frame number.*/
   eNB_index_t eNB_index;     /*!< \brief  valid for UE indicating the index of connected eNB(s)      */
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
index 62aa101a500..42b9f171cea 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
@@ -368,8 +368,8 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
   ret->set_security = nr_pdcp_entity_set_security;
   ret->set_time     = nr_pdcp_entity_set_time;
 
-  ret->delete = nr_pdcp_entity_delete;
-
+  ret->delete_entity = nr_pdcp_entity_delete;
+  
   ret->deliver_sdu = deliver_sdu;
   ret->deliver_sdu_data = deliver_sdu_data;
 
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
index fbcc2b96cd3..49e9c4142b5 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
@@ -39,7 +39,7 @@ typedef struct nr_pdcp_entity_t {
   void (*recv_pdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size);
   void (*recv_sdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size,
                    int sdu_id);
-  void (*delete)(struct nr_pdcp_entity_t *entity);
+  void (*delete_entity)(struct nr_pdcp_entity_t *entity);
 
   /* set_security: pass -1 to integrity_algorithm / ciphering_algorithm
    *               to keep the current algorithm
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
index 7d1e2f49318..3c999161698 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
@@ -36,7 +36,8 @@
 #include "pdcp.h"
 #include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
 #include <openair3/ocp-gtpu/gtp_itf.h>
-#include "openair2/SDAP/nr_sdap/nr_sdap_gnb.h"
+#include "openair2/SDAP/nr_sdap/nr_sdap.h"
+#include "nr_pdcp_oai_api.h"
 
 #define TODO do { \
     printf("%s:%d:%s: todo\n", __FILE__, __LINE__, __FUNCTION__); \
@@ -438,9 +439,13 @@ static void *enb_tun_read_thread(void *_)
 
     ctxt.rnti = rnti;
 
-    pdcp_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED,
-                  RLC_SDU_CONFIRM_NO, len, (unsigned char *)rx_buf,
-                  PDCP_TRANSMISSION_MODE_DATA, NULL, NULL);
+    ctxt.sdap.qfi = 7;
+    ctxt.sdap.rqi = 0;
+    ctxt.sdap.pdusession_id = 10;
+
+    sdap_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED,
+                      RLC_SDU_CONFIRM_NO, len, (unsigned char *)rx_buf,
+                      PDCP_TRANSMISSION_MODE_DATA, NULL, NULL);
   }
 
   return NULL;
@@ -481,9 +486,13 @@ static void *ue_tun_read_thread(void *_)
 
     ctxt.rnti = rnti;
 
-    pdcp_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED,
-                  RLC_SDU_CONFIRM_NO, len, (unsigned char *)rx_buf,
-                  PDCP_TRANSMISSION_MODE_DATA, NULL, NULL);
+    ctxt.sdap.dc = SDAP_HDR_UL_DATA_PDU;
+    ctxt.sdap.qfi = 7;
+    ctxt.sdap.pdusession_id = 10;
+
+    sdap_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED,
+                      RLC_SDU_CONFIRM_NO, len, (unsigned char *)rx_buf,
+                      PDCP_TRANSMISSION_MODE_DATA, NULL, NULL);
   }
 
   return NULL;
@@ -607,28 +616,13 @@ uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id)
 static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
                             char *buf, int size)
 {
-  extern int nas_sock_fd[];
-  int len;
   nr_pdcp_ue_t *ue = _ue;
-  MessageDef  *message_p;
-  uint8_t     *gtpu_buffer_p;
   int rb_id;
   int i;
 
   if (IS_SOFTMODEM_NOS1 || UE_NAS_USE_TUN) {
-    LOG_D(PDCP, "IP packet received, to be sent to TUN interface");
-
-    if(entity->has_sdapDLheader){
-      size -= SDAP_HDR_LENGTH;
-      len = write(nas_sock_fd[0], &buf[SDAP_HDR_LENGTH], size);
-    } else {
-      len = write(nas_sock_fd[0], buf, size);
-    }
-
-    if (len != size) {
-      LOG_E(PDCP, "%s:%d:%s: fatal error %d: %s\n", __FILE__, __LINE__, __FUNCTION__, errno, strerror(errno));
-    }
-    
+    LOG_D(PDCP, "IP packet received with size %d, to be sent to SDAP interface, UE rnti: %d\n", size, ue->rnti);
+    sdap_data_ind(entity, ue->rnti, buf, size);
   }
   else{
     for (i = 0; i < 5; i++) {
@@ -644,31 +638,9 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
 
     rb_found:
     {
-      int offset=0;
-      if (entity->has_sdap == 1 && entity->has_sdapULheader == 1)
-	offset = 1; // this is the offset of the SDAP header in bytes
-
-      message_p = itti_alloc_new_message_sized(TASK_PDCP_ENB, 0,
-					       GTPV1U_GNB_TUNNEL_DATA_REQ,
-					       sizeof(gtpv1u_gnb_tunnel_data_req_t) + size
-					       + GTPU_HEADER_OVERHEAD_MAX - offset);
-      AssertFatal(message_p != NULL, "OUT OF MEMORY");
-
-      gtpv1u_gnb_tunnel_data_req_t *req=&GTPV1U_GNB_TUNNEL_DATA_REQ(message_p);
-      gtpu_buffer_p = (uint8_t*)(req+1);
-      memcpy(gtpu_buffer_p+GTPU_HEADER_OVERHEAD_MAX, buf+offset, size-offset);
-      req->buffer              = gtpu_buffer_p;
-      req->length              = size-offset;
-      req->offset              = GTPU_HEADER_OVERHEAD_MAX;
-      req->rnti                = ue->rnti;
-      req->pdusession_id       = entity->pdusession_id;
-      if (offset==1) {
-        LOG_I(PDCP, "%s() (drb %d) SDAP header %2x\n",__func__, rb_id, buf[0]);
-        sdap_gnb_ul_header_handler(buf[0]); // Handler for the UL gNB SDAP Header
-      }
-      LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size-offset);
-      itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p);
-   }
+      LOG_D(PDCP, "%s() (drb %d) sending message to SDAP size %d\n", __func__, rb_id, size);
+      sdap_data_ind(entity, ue->rnti, buf, size);
+    }
   }
 }
 
@@ -967,6 +939,9 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s,
   int has_sdap = 0;
   int has_sdapULheader=0;
   int has_sdapDLheader=0;
+  boolean_t is_sdap_DefaultDRB = false;
+  NR_QFI_t *mappedQFIs2Add = NULL;
+  uint8_t mappedQFIs2AddCount=0;
   if (s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity)
      pdusession_id = s->cnAssociation->choice.eps_BearerIdentity;
   else {
@@ -978,6 +953,10 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s,
     has_sdap = 1;
     has_sdapULheader = s->cnAssociation->choice.sdap_Config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present ? 1 : 0;
     has_sdapDLheader = s->cnAssociation->choice.sdap_Config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present ? 1 : 0;
+    is_sdap_DefaultDRB = s->cnAssociation->choice.sdap_Config->defaultDRB == true ? 1 : 0;
+    mappedQFIs2Add = (NR_QFI_t*)s->cnAssociation->choice.sdap_Config->mappedQoS_FlowsToAdd->list.array[0]; 
+    mappedQFIs2AddCount = s->cnAssociation->choice.sdap_Config->mappedQoS_FlowsToAdd->list.count;
+    LOG_D(SDAP, "Captured mappedQoS_FlowsToAdd from RRC: %ld \n", *mappedQFIs2Add);
   }
   /* TODO(?): accept different UL and DL SN sizes? */
   if (sn_size_ul != sn_size_dl) {
@@ -1009,6 +988,14 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s,
     nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb);
 
     LOG_D(PDCP, "%s:%d:%s: added drb %d to ue rnti %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+
+    new_nr_sdap_entity(rnti,
+                       pdusession_id,
+                       is_sdap_DefaultDRB,
+                       drb_id,
+                       mappedQFIs2Add,
+                       mappedQFIs2AddCount);
+    LOG_D(SDAP, "Added SDAP entity to ue rnti %x with pdusession_id %d\n", rnti, pdusession_id);
   }
   nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
 }
@@ -1140,7 +1127,7 @@ void nr_DRB_preconfiguration(uint16_t crnti)
   NR_DRB_ToAddMod_t *drb_ToAddMod = calloc(1,sizeof(*drb_ToAddMod));
   drb_ToAddMod->cnAssociation = calloc(1,sizeof(*drb_ToAddMod->cnAssociation));
   drb_ToAddMod->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity;
-  drb_ToAddMod->cnAssociation->choice.eps_BearerIdentity= 5;
+  drb_ToAddMod->cnAssociation->choice.eps_BearerIdentity= 10;
   drb_ToAddMod->drb_Identity = 1;
   drb_ToAddMod->reestablishPDCP = NULL;
   drb_ToAddMod->recoverPDCP = NULL;
@@ -1450,3 +1437,12 @@ void nr_pdcp_tick(int frame, int subframe)
     nr_pdcp_wakeup_timer_thread(nr_pdcp_current_time);
   }
 }
+
+nr_pdcp_entity_t *nr_pdcp_find_entity_sdap(int rnti, uint8_t sdap_drb_id){
+  nr_pdcp_ue_t *ue;
+  ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, rnti);
+  if(ue->drb[sdap_drb_id-1])
+   return ue->drb[sdap_drb_id-1];
+  
+  return NULL;
+}
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h
new file mode 100644
index 00000000000..59e366ca46b
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h
@@ -0,0 +1,3 @@
+#include "openair2/COMMON/platform_types.h"
+
+nr_pdcp_entity_t *nr_pdcp_find_entity_sdap(int rnti, uint8_t sdap_drb_id);
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
index 160c5ebb226..1f21593c630 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
@@ -127,11 +127,11 @@ void nr_pdcp_manager_remove_ue(nr_pdcp_ue_manager_t *_m, int rnti)
 
   for (j = 0; j < 2; j++)
     if (ue->srb[j] != NULL)
-      ue->srb[j]->delete(ue->srb[j]);
+      ue->srb[j]->delete_entity(ue->srb[j]);
 
   for (j = 0; j < 5; j++)
     if (ue->drb[j] != NULL)
-      ue->drb[j]->delete(ue->drb[j]);
+      ue->drb[j]->delete_entity(ue->drb[j]);
 
   free(ue);
 
diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c
index 86b767f83cd..5ea118f64ec 100755
--- a/openair2/RRC/NR/rrc_gNB.c
+++ b/openair2/RRC/NR/rrc_gNB.c
@@ -818,7 +818,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration(
   uint8_t                        buffer[RRC_BUF_SIZE];
   uint16_t                       size;
   int                            qos_flow_index = 0;
-  NR_QFI_t                       qfi = 0;
   int                            pdu_sessions_done = 0;
   int i;
   NR_CellGroupConfig_t *cellGroupConfig;
@@ -870,14 +869,15 @@ rrc_gNB_generate_dedicatedRRCReconfiguration(
     memset(sdap_config, 0, sizeof(NR_SDAP_Config_t));
     sdap_config->pdu_Session = ue_context_pP->ue_context.pduSession[i].param.pdusession_id;
     sdap_config->sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present;
-    sdap_config->sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent;
+    sdap_config->sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present;
     sdap_config->defaultDRB = TRUE;
     sdap_config->mappedQoS_FlowsToAdd = calloc(1, sizeof(struct NR_SDAP_Config__mappedQoS_FlowsToAdd));
     memset(sdap_config->mappedQoS_FlowsToAdd, 0, sizeof(struct NR_SDAP_Config__mappedQoS_FlowsToAdd));
 
     for (qos_flow_index = 0; qos_flow_index < ue_context_pP->ue_context.pduSession[i].param.nb_qos; qos_flow_index++) {
-      qfi = ue_context_pP->ue_context.pduSession[i].param.qos[qos_flow_index].qfi;
-      ASN_SEQUENCE_ADD(&sdap_config->mappedQoS_FlowsToAdd->list, &qfi);
+      NR_QFI_t *qfi = calloc(1, sizeof(NR_QFI_t));
+      *qfi = ue_context_pP->ue_context.pduSession[i].param.qos[qos_flow_index].qfi;
+      ASN_SEQUENCE_ADD(&sdap_config->mappedQoS_FlowsToAdd->list, qfi);
     }
     sdap_config->mappedQoS_FlowsToRelease = NULL;
     DRB_config->cnAssociation->choice.sdap_Config = sdap_config;
diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c
new file mode 100644
index 00000000000..674dd700b1d
--- /dev/null
+++ b/openair2/SDAP/nr_sdap/nr_sdap.c
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#include "nr_sdap.h"
+
+boolean_t sdap_data_req(protocol_ctxt_t *ctxt_p,
+                        const srb_flag_t srb_flag,
+                        const rb_id_t rb_id,
+                        const mui_t mui,
+                        const confirm_t confirm,
+                        const sdu_size_t sdu_buffer_size,
+                        unsigned char *const sdu_buffer,
+                        const pdcp_transmission_mode_t pt_mode,
+                        const uint32_t *sourceL2Id,
+                        const uint32_t *destinationL2Id) {
+  nr_sdap_entity_t *sdap_entity;
+  sdap_entity = nr_sdap_get_entity(ctxt_p->rnti, ctxt_p->sdap.pdusession_id);
+
+  if(sdap_entity == NULL) {
+    LOG_E(SDAP, "%s:%d:%s: Entity not found with ue rnti: %x and pdusession id: %d\n", __FILE__, __LINE__, __FUNCTION__, ctxt_p->rnti, ctxt_p->sdap.pdusession_id);
+    return 0;
+  }
+
+  boolean_t ret = sdap_entity->tx_entity(sdap_entity,
+                                         ctxt_p,
+                                         srb_flag,
+                                         rb_id,
+                                         mui,
+                                         confirm,
+                                         sdu_buffer_size,
+                                         sdu_buffer,
+                                         pt_mode,
+                                         sourceL2Id,
+                                         destinationL2Id);
+  return ret;
+}
+
+void sdap_data_ind(nr_pdcp_entity_t *pdcp_entity,
+                   int rnti,
+                   char *buf,
+                   int size) {
+  nr_sdap_entity_t *sdap_entity;
+  sdap_entity = nr_sdap_get_entity(rnti, pdcp_entity->pdusession_id);
+
+  if(sdap_entity == NULL) {
+    LOG_E(SDAP, "%s:%d:%s: Entity not found\n", __FILE__, __LINE__, __FUNCTION__);
+    return;
+  }
+
+  sdap_entity->rx_entity(sdap_entity,
+                         pdcp_entity,
+                         rnti,
+                         buf,
+                         size);
+}
diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h
new file mode 100644
index 00000000000..e4e8004e2d8
--- /dev/null
+++ b/openair2/SDAP/nr_sdap/nr_sdap.h
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#ifndef _NR_SDAP_GNB_H_
+#define _NR_SDAP_GNB_H_
+
+#include "openair2/COMMON/platform_types.h"
+#include "common/utils/LOG/log.h"
+#include "nr_sdap_entity.h"
+
+/*
+ * TS 37.324 4.4 Functions
+ * Transfer of user plane data
+ * Downlink - gNB
+ * Uplink   - nrUE
+ */
+boolean_t sdap_data_req(protocol_ctxt_t *ctxt_p,
+                        const srb_flag_t srb_flag,
+                        const rb_id_t rb_id,
+                        const mui_t mui,
+                        const confirm_t confirm,
+                        const sdu_size_t sdu_buffer_size,
+                        unsigned char *const sdu_buffer,
+                        const pdcp_transmission_mode_t pt_mode,
+                        const uint32_t *sourceL2Id,
+                        const uint32_t *destinationL2Id
+                       );
+
+/*
+ * TS 37.324 4.4 Functions
+ * Transfer of user plane data
+ * Uplink   - gNB
+ * Downlink - nrUE
+ */
+void sdap_data_ind(nr_pdcp_entity_t *pdcp_entity,
+                   int rnti,
+                   char *buf,
+                   int size
+                  );
+
+#endif
diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c
new file mode 100644
index 00000000000..028653372fd
--- /dev/null
+++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c
@@ -0,0 +1,474 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#include "nr_sdap_entity.h"
+#include "common/utils/LOG/log.h"
+#include <openair2/LAYER2/PDCP_v10.1.0/pdcp.h>
+#include <openair3/ocp-gtpu/gtp_itf.h>
+#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+typedef struct {
+  nr_sdap_entity_t *sdap_entity_llist;
+} nr_sdap_entity_info;
+
+static nr_sdap_entity_info sdap_info;
+
+static boolean_t nr_sdap_tx_entity(nr_sdap_entity_t *entity,
+                                   protocol_ctxt_t *ctxt_p,
+                                   const srb_flag_t srb_flag,
+                                   const rb_id_t rb_id,
+                                   const mui_t mui,
+                                   const confirm_t confirm,
+                                   const sdu_size_t sdu_buffer_size,
+                                   unsigned char *const sdu_buffer,
+                                   const pdcp_transmission_mode_t pt_mode,
+                                   const uint32_t *sourceL2Id,
+                                   const uint32_t *destinationL2Id
+                                  ) {
+  /* The offset of the SDAP header, it might be 0 if the has_sdap is not true in the pdcp entity. */
+  int offset=0;
+  boolean_t ret=false;
+  /*Hardcode DRB ID given from upper layer (ue/enb_tun_read_thread rb_id), it will change if we have SDAP*/
+  rb_id_t sdap_drb_id = rb_id;
+  int pdcp_ent_has_sdap = 0;
+
+  if(sdu_buffer == NULL) {
+    LOG_E(SDAP, "%s:%d:%s: NULL sdu_buffer \n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  uint8_t sdap_buf[SDAP_MAX_PDU];
+  nr_pdcp_entity_t *pdcp_entity = entity->qfi2drb_map(entity, ctxt_p->sdap.qfi, rb_id);
+
+  if(pdcp_entity){
+    sdap_drb_id = pdcp_entity->rb_id;
+    pdcp_ent_has_sdap = pdcp_entity->has_sdap;
+  }
+
+  if(!pdcp_ent_has_sdap){
+    ret = pdcp_data_req(ctxt_p,
+                        srb_flag,
+                        sdap_drb_id,
+                        mui,
+                        confirm,
+                        sdu_buffer_size,
+                        sdu_buffer,
+                        pt_mode,
+                        sourceL2Id,
+                        destinationL2Id);
+
+    if(!ret)
+      LOG_E(SDAP, "%s:%d:%s: PDCP refused PDU\n", __FILE__, __LINE__, __FUNCTION__);
+
+    return ret;
+  }
+
+  if(sdu_buffer_size == 0 || sdu_buffer_size > 8999) {
+    LOG_E(SDAP, "%s:%d:%s: NULL or 0 or exceeded sdu_buffer_size (over max PDCP SDU)\n", __FILE__, __LINE__, __FUNCTION__);
+    return 0;
+  }
+
+  if(ctxt_p->enb_flag) { // gNB
+    offset = SDAP_HDR_LENGTH;
+    /*
+     * TS 37.324 4.4 Functions
+     * marking QoS flow ID in DL packets.
+     *
+     * Construct the DL SDAP data PDU.
+     */
+    nr_sdap_dl_hdr_t sdap_hdr;
+    sdap_hdr.QFI = ctxt_p->sdap.qfi;
+    sdap_hdr.RQI = ctxt_p->sdap.rqi;
+    sdap_hdr.RDI = 0; // SDAP Hardcoded Value
+    /* Add the SDAP DL Header to the buffer */
+    memcpy(&sdap_buf[0], &sdap_hdr, SDAP_HDR_LENGTH);
+    memcpy(&sdap_buf[SDAP_HDR_LENGTH], sdu_buffer, sdu_buffer_size);
+    LOG_D(SDAP, "TX Entity QFI: %u \n", sdap_hdr.QFI);
+    LOG_D(SDAP, "TX Entity RQI: %u \n", sdap_hdr.RQI);
+    LOG_D(SDAP, "TX Entity RDI: %u \n", sdap_hdr.RDI);
+  } else { // nrUE
+    offset = SDAP_HDR_LENGTH;
+    /*
+     * TS 37.324 4.4 Functions
+     * marking QoS flow ID in UL packets.
+     *
+     * 5.2.1 Uplink
+     * construct the UL SDAP data PDU as specified in the subclause 6.2.2.3.
+     */
+    nr_sdap_ul_hdr_t sdap_hdr;
+    sdap_hdr.QFI = ctxt_p->sdap.qfi;
+    sdap_hdr.R = 0;
+    sdap_hdr.DC = ctxt_p->sdap.dc;
+    /* Add the SDAP UL Header to the buffer */
+    memcpy(&sdap_buf[0], &sdap_hdr, SDAP_HDR_LENGTH);
+    memcpy(&sdap_buf[SDAP_HDR_LENGTH], sdu_buffer, sdu_buffer_size);
+    LOG_D(SDAP, "TX Entity QFI: %u \n", sdap_hdr.QFI);
+    LOG_D(SDAP, "TX Entity R: %u \n", sdap_hdr.R);
+    LOG_D(SDAP, "TX Entity DC: %u \n", sdap_hdr.DC);
+  }
+
+  /*
+   * TS 37.324 5.2 Data transfer
+   * 5.2.1 Uplink UE side
+   * submit the constructed UL SDAP data PDU to the lower layers
+   *
+   * Downlink gNB side
+   */
+  ret = pdcp_data_req(ctxt_p,
+                      srb_flag,
+                      sdap_drb_id,
+                      mui,
+                      confirm,
+                      sdu_buffer_size+offset,
+                      sdap_buf,
+                      pt_mode,
+                      sourceL2Id,
+                      destinationL2Id);
+
+  if(!ret)
+    LOG_E(SDAP, "%s:%d:%s: PDCP refused PDU\n", __FILE__, __LINE__, __FUNCTION__);
+
+  return ret;
+}
+
+static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
+                              nr_pdcp_entity_t *pdcp_entity,
+                              int rnti,
+                              char *buf,
+                              int size) {
+  /* The offset of the SDAP header, it might be 0 if the has_sdap is not true in the pdcp entity. */
+  int offset=0;
+
+  if(pdcp_entity->is_gnb) { // gNB
+    if(pdcp_entity->has_sdap && pdcp_entity->has_sdapULheader ) { // Handling the SDAP Header
+      offset = SDAP_HDR_LENGTH;
+      nr_sdap_ul_hdr_t *sdap_hdr = (nr_sdap_ul_hdr_t *)buf;
+      LOG_D(SDAP, "RX Entity Received QFI : %u\n", sdap_hdr->QFI);
+      LOG_D(SDAP, "RX Entity Received Reserved bit : %u\n", sdap_hdr->R);
+      LOG_D(SDAP, "RX Entity Received DC bit : %u\n", sdap_hdr->DC);
+
+      switch (sdap_hdr->DC) {
+        case SDAP_HDR_UL_DATA_PDU:
+          LOG_D(SDAP, "RX Entity Received SDAP Data PDU\n");
+          break;
+
+        case SDAP_HDR_UL_CTRL_PDU:
+          LOG_D(SDAP, "RX Entity Received SDAP Control PDU\n");
+          break;
+      }
+    }
+
+    // Pushing SDAP SDU to GTP-U Layer
+    MessageDef *message_p;
+    uint8_t *gtpu_buffer_p;
+    gtpu_buffer_p = itti_malloc(TASK_PDCP_ENB, TASK_GTPV1_U, size + GTPU_HEADER_OVERHEAD_MAX - offset);
+    AssertFatal(gtpu_buffer_p != NULL, "OUT OF MEMORY");
+    memcpy(&gtpu_buffer_p[GTPU_HEADER_OVERHEAD_MAX], buf+offset, size-offset);
+    message_p = itti_alloc_new_message(TASK_PDCP_ENB, 0 , GTPV1U_GNB_TUNNEL_DATA_REQ);
+    AssertFatal(message_p != NULL, "OUT OF MEMORY");
+    GTPV1U_GNB_TUNNEL_DATA_REQ(message_p).buffer = gtpu_buffer_p;
+    GTPV1U_GNB_TUNNEL_DATA_REQ(message_p).length              = size-offset;
+    GTPV1U_GNB_TUNNEL_DATA_REQ(message_p).offset              = GTPU_HEADER_OVERHEAD_MAX;
+    GTPV1U_GNB_TUNNEL_DATA_REQ(message_p).rnti                = rnti;
+    GTPV1U_GNB_TUNNEL_DATA_REQ(message_p).pdusession_id       = pdcp_entity->pdusession_id;
+    LOG_D(SDAP, "%s()  sending message to gtp size %d\n", __func__,  size-offset);
+    itti_send_msg_to_task(TASK_VARIABLE, INSTANCE_DEFAULT, message_p);
+  } else { //nrUE
+    /*
+     * TS 37.324 5.2 Data transfer
+     * 5.2.2 Downlink
+     * if the DRB from which this SDAP data PDU is received is configured by RRC with the presence of SDAP header.
+     */
+    if(pdcp_entity->has_sdap && pdcp_entity->has_sdapDLheader) { // Handling the SDAP Header
+      offset = SDAP_HDR_LENGTH;
+      /*
+       * TS 37.324 5.2 Data transfer
+       * 5.2.2 Downlink
+       * retrieve the SDAP SDU from the DL SDAP data PDU as specified in the subclause 6.2.2.2.
+       */
+      nr_sdap_dl_hdr_t *sdap_hdr = (nr_sdap_dl_hdr_t *)buf;
+      LOG_D(SDAP, "RX Entity Received QFI : %u\n", sdap_hdr->QFI);
+      LOG_D(SDAP, "RX Entity Received RQI : %u\n", sdap_hdr->RQI);
+      LOG_D(SDAP, "RX Entity Received RDI : %u\n", sdap_hdr->RDI);
+
+      /*
+       * TS 37.324 5.2 Data transfer
+       * 5.2.2 Downlink
+       * Perform reflective QoS flow to DRB mapping as specified in the subclause 5.3.2.
+       */
+      if(sdap_hdr->RDI == SDAP_REFLECTIVE_MAPPING) {
+        /*
+         * TS 37.324 5.3 QoS flow to DRB Mapping 
+         * 5.3.2 Reflective mapping
+         * If there is no stored QoS flow to DRB mapping rule for the QoS flow and a default DRB is configured.
+         */
+        if(!entity->qfi2drb_table[sdap_hdr->QFI] && entity->default_drb->rb_id){
+          nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
+          nr_pdcp_entity_t *sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, pdcp_entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI);
+          entity->sdap_submit_ctrl_pdu(rnti, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
+        }
+
+        /*
+         * TS 37.324 5.3 QoS flow to DRB mapping 
+         * 5.3.2 Reflective mapping
+         * if the stored QoS flow to DRB mapping rule for the QoS flow 
+         * is different from the QoS flow to DRB mapping of the DL SDAP data PDU
+         * and
+         * the DRB according to the stored QoS flow to DRB mapping rule is configured by RRC
+         * with the presence of UL SDAP header
+         */
+        if( (pdcp_entity->rb_id != entity->qfi2drb_table[sdap_hdr->QFI]->rb_id) && 
+             pdcp_entity->has_sdapULheader ){
+          nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
+          nr_pdcp_entity_t *sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, pdcp_entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI);
+          entity->sdap_submit_ctrl_pdu(rnti, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
+        }
+
+        /*
+         * TS 37.324 5.3 QoS flow to DRB Mapping 
+         * 5.3.2 Reflective mapping
+         * store the QoS flow to DRB mapping of the DL SDAP data PDU as the QoS flow to DRB mapping rule for the UL. 
+         */ 
+        entity->qfi2drb_table[sdap_hdr->QFI]->rb_id = pdcp_entity->rb_id;
+      }
+
+      /*
+       * TS 37.324 5.2 Data transfer
+       * 5.2.2 Downlink
+       * perform RQI handling as specified in the subclause 5.4
+       */
+      if(sdap_hdr->RQI == SDAP_RQI_HANDLING) {
+        LOG_W(SDAP, "UE - TODD 5.4\n");
+      }
+    } /*  else - retrieve the SDAP SDU from the DL SDAP data PDU as specified in the subclause 6.2.2.1 */
+
+    /*
+     * TS 37.324 5.2 Data transfer
+     * 5.2.2 Downlink
+     * deliver the retrieved SDAP SDU to the upper layer.
+     */
+    extern int nas_sock_fd[];
+    int len = write(nas_sock_fd[0], &buf[offset], size-offset);
+    LOG_D(SDAP, "RX Entity len : %d\n", len);
+    LOG_D(SDAP, "RX Entity size : %d\n", size);
+    LOG_D(SDAP, "RX Entity offset : %d\n", offset);
+
+    if (len != size-offset)
+      LOG_E(SDAP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+  }
+}
+
+void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, uint8_t drb){
+  if(qfi < SDAP_MAX_QFI &&
+     qfi > SDAP_MAP_RULE_EMPTY &&
+     drb > 0 &&
+     drb <= AVLBL_DRB)
+  {
+    nr_pdcp_entity_t *pdcp_entity;
+    pdcp_entity = nr_pdcp_find_entity_sdap(entity->rnti, drb);
+
+    if(!pdcp_entity){
+      LOG_D(SDAP, "Map Update failed - PDCP Entity does not exist, should create it\n");
+      LOG_D(SDAP, "Map Update failed - Mapping to default DRB\n");
+      entity->qfi2drb_table[qfi] = entity->default_drb;
+    }
+
+    entity->qfi2drb_table[qfi] = pdcp_entity;
+    LOG_D(SDAP, "Updated QFI to DRB Map: QFI %u -> DRB %d \n", qfi, entity->qfi2drb_table[qfi]->rb_id);
+  }
+}
+
+void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi){
+  entity->qfi2drb_table[qfi] = SDAP_NO_MAPPING_RULE;
+  LOG_D(SDAP, "Deleted QFI to DRB Map for QFI %u \n", qfi);
+}
+
+nr_pdcp_entity_t *nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi, long upper_layer_rb_id){
+  nr_pdcp_entity_t *pdcp_entity;
+
+  pdcp_entity = entity->qfi2drb_table[qfi];
+
+  if(pdcp_entity){
+    return pdcp_entity;
+  } else if(entity->default_drb) {
+    LOG_D(SDAP, "Mapped QFI %u to Default DRB\n", qfi);
+    entity->qfi2drb_map_update(entity, qfi, entity->default_drb->rb_id);
+    return entity->default_drb;
+  } else {
+    /* Update map for Hardcode DRB ID given from upper layer (ue/enb_tun_read_thread rb_id)*/
+    entity->qfi2drb_map_update(entity, qfi, upper_layer_rb_id);
+    return SDAP_MAP_RULE_EMPTY;
+  }
+
+  return pdcp_entity;
+}
+
+nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi){
+  nr_sdap_ul_hdr_t sdap_end_marker_hdr;
+  sdap_end_marker_hdr.QFI = qfi;
+  sdap_end_marker_hdr.R = 0;
+  sdap_end_marker_hdr.DC = SDAP_HDR_UL_CTRL_PDU;
+  LOG_D(SDAP, "Constructed Control PDU with QFI:%u R:%u DC:%u \n", sdap_end_marker_hdr.QFI,
+                                                                   sdap_end_marker_hdr.R,
+                                                                   sdap_end_marker_hdr.DC);
+  return sdap_end_marker_hdr;
+}
+
+nr_pdcp_entity_t *nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, nr_pdcp_entity_t *pdcp_entity, int map_type, uint8_t dl_qfi){
+  nr_pdcp_entity_t *drb_of_endmarker = NULL;
+  if(map_type == SDAP_CTRL_PDU_MAP_DEF_DRB){
+    drb_of_endmarker = entity->default_drb;
+    LOG_D(SDAP, "Mapped Control PDU to default drb\n");
+  }
+  if(map_type == SDAP_CTRL_PDU_MAP_RULE_DRB){
+    drb_of_endmarker = entity->qfi2drb_map(entity, dl_qfi, pdcp_entity->rb_id);
+    LOG_D(SDAP, "Mapped Control PDU according to the mapping rule, qfi %u \n", dl_qfi);
+  }
+  return drb_of_endmarker;
+}
+
+void nr_sdap_submit_ctrl_pdu(int rnti, nr_pdcp_entity_t *sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu){
+  if(sdap_ctrl_pdu_drb){
+    sdap_ctrl_pdu_drb->recv_sdu(sdap_ctrl_pdu_drb, (char*)&ctrl_pdu, SDAP_HDR_LENGTH, RLC_MUI_UNDEFINED);
+    LOG_D(SDAP, "Sent Control PDU to PDCP Layer.\n");
+  }
+}
+
+void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity,
+                               nr_pdcp_entity_t *pdcp_entity,
+                               uint16_t rnti,
+                               NR_QFI_t *mapped_qfi_2_add,
+                               uint8_t mappedQFIs2AddCount,
+                               uint8_t drb_identity)
+{
+  uint8_t qfi = 0;
+
+  for(int i = 0; i < mappedQFIs2AddCount; i++){
+    qfi = mapped_qfi_2_add[i];
+    if(existing_sdap_entity->default_drb && existing_sdap_entity->qfi2drb_table[qfi] == SDAP_NO_MAPPING_RULE){
+      nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi);
+      nr_pdcp_entity_t *sdap_ctrl_pdu_drb = existing_sdap_entity->sdap_map_ctrl_pdu(existing_sdap_entity, pdcp_entity, SDAP_CTRL_PDU_MAP_DEF_DRB, qfi);
+      existing_sdap_entity->sdap_submit_ctrl_pdu(rnti, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
+    }
+    if(existing_sdap_entity->qfi2drb_table[qfi]->rb_id != drb_identity && pdcp_entity->has_sdapULheader){
+      nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi);
+      nr_pdcp_entity_t *sdap_ctrl_pdu_drb = existing_sdap_entity->sdap_map_ctrl_pdu(existing_sdap_entity, pdcp_entity, SDAP_CTRL_PDU_MAP_RULE_DRB, qfi);
+      existing_sdap_entity->sdap_submit_ctrl_pdu(rnti, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
+    }
+  }
+}
+
+nr_sdap_entity_t *new_nr_sdap_entity(uint16_t rnti,
+                                     int pdusession_id,
+                                     boolean_t is_defaultDRB,
+                                     uint8_t drb_identity,
+                                     NR_QFI_t *mapped_qfi_2_add,
+                                     uint8_t mappedQFIs2AddCount)
+{
+  if(nr_sdap_get_entity(rnti, pdusession_id)) {
+    LOG_E(SDAP, "SDAP Entity for UE already exists.\n");
+    nr_sdap_entity_t *existing_sdap_entity = nr_sdap_get_entity(rnti, pdusession_id);
+    nr_pdcp_entity_t *pdcp_entity = existing_sdap_entity->default_drb;
+    nr_sdap_ue_qfi2drb_config(existing_sdap_entity, pdcp_entity, rnti, mapped_qfi_2_add, mappedQFIs2AddCount, drb_identity);
+    return existing_sdap_entity;
+  }
+
+  nr_sdap_entity_t *sdap_entity;
+  sdap_entity = calloc(1, sizeof(nr_sdap_entity_t));
+
+  if(sdap_entity == NULL) {
+    LOG_E(SDAP, "SDAP Entity creation failed, out of memory\n");
+    exit(1);
+  }
+
+  sdap_entity->rnti = rnti;
+  sdap_entity->pdusession_id = pdusession_id;
+
+  sdap_entity->tx_entity = nr_sdap_tx_entity;
+  sdap_entity->rx_entity = nr_sdap_rx_entity;
+
+  sdap_entity->sdap_construct_ctrl_pdu = nr_sdap_construct_ctrl_pdu;
+  sdap_entity->sdap_map_ctrl_pdu = nr_sdap_map_ctrl_pdu;
+  sdap_entity->sdap_submit_ctrl_pdu = nr_sdap_submit_ctrl_pdu;
+
+  sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update;
+  sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del;
+  sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map;
+
+  if(is_defaultDRB) {
+    nr_pdcp_entity_t *pdcp_entity = nr_pdcp_find_entity_sdap(sdap_entity->rnti, drb_identity);
+    sdap_entity->default_drb = pdcp_entity;
+    LOG_I(SDAP, "Default DRB for the created SDAP entity: %d \n", sdap_entity->default_drb->rb_id);
+
+    if(mappedQFIs2AddCount) {
+      for (int i = 0; i < mappedQFIs2AddCount; i++)
+      {
+        LOG_D(SDAP, "Mapped QFI to Add : %ld \n", mapped_qfi_2_add[i]);
+        sdap_entity->qfi2drb_map_update(sdap_entity, mapped_qfi_2_add[i], sdap_entity->default_drb->rb_id);
+      }
+    }
+  }
+
+  sdap_entity->next_entity = sdap_info.sdap_entity_llist;
+  sdap_info.sdap_entity_llist = sdap_entity;
+  return sdap_entity;
+}
+
+nr_sdap_entity_t *nr_sdap_get_entity(uint16_t rnti, int pdusession_id) {
+  nr_sdap_entity_t *sdap_entity;
+  sdap_entity = sdap_info.sdap_entity_llist;
+
+  if(sdap_entity == NULL)
+    return NULL;
+
+  while(sdap_entity->rnti != rnti && sdap_entity->next_entity != NULL) {
+    sdap_entity = sdap_entity->next_entity;
+  }
+
+  if (sdap_entity->rnti == rnti && sdap_entity->pdusession_id == pdusession_id)
+    return sdap_entity;
+
+  return NULL;
+}
+
+void delete_nr_sdap_entity(uint16_t rnti) {
+  nr_sdap_entity_t *entityPtr, *entityPrev = NULL;
+  entityPtr = sdap_info.sdap_entity_llist;
+
+  if(entityPtr->rnti == rnti) {
+    sdap_info.sdap_entity_llist = sdap_info.sdap_entity_llist->next_entity;
+    free(entityPtr);
+  } else {
+    while(entityPtr->rnti != rnti && entityPtr->next_entity != NULL) {
+      entityPrev = entityPtr;
+      entityPtr = entityPtr->next_entity;
+    }
+
+    if(entityPtr->rnti != rnti) {
+      entityPrev->next_entity = entityPtr->next_entity;
+      free(entityPtr);
+    }
+  }
+}
diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h
new file mode 100644
index 00000000000..46c9ea37749
--- /dev/null
+++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#ifndef _NR_SDAP_ENTITY_H_
+#define _NR_SDAP_ENTITY_H_
+
+#include <stdint.h>
+#include "openair2/COMMON/platform_types.h"
+#include "openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h"
+#include "NR_RadioBearerConfig.h"
+
+#define SDAP_BITMASK_DC             (0x80)
+#define SDAP_BITMASK_R              (0x40)
+#define SDAP_BITMASK_QFI            (0x3F)
+#define SDAP_BITMASK_RQI            (0x40)
+#define SDAP_HDR_UL_DATA_PDU        (1)
+#define SDAP_HDR_UL_CTRL_PDU        (0)
+#define SDAP_HDR_LENGTH             (1)
+#define SDAP_MAX_QFI                (64)
+#define SDAP_MAP_RULE_EMPTY         (0)
+#define AVLBL_DRB                   (5)
+#define SDAP_NO_MAPPING_RULE        (0)
+#define SDAP_REFLECTIVE_MAPPING     (1)
+#define SDAP_RQI_HANDLING           (1)
+#define SDAP_CTRL_PDU_MAP_DEF_DRB   (0)
+#define SDAP_CTRL_PDU_MAP_RULE_DRB  (1)
+#define SDAP_MAX_PDU                (9000)
+
+/*
+ * The values of QoS Flow ID (QFI) and Reflective QoS Indication,
+ * are located in the PDU Session Container, which is conveyed by
+ * the GTP-U Extension Header. Inside the DL PDU SESSION INFORMATION frame.
+ * TS 38.415 Fig. 5.5.2.1-1
+ */
+typedef struct nr_sdap_dl_hdr_s {
+  uint8_t QFI:6;
+  uint8_t RQI:1;
+  uint8_t RDI:1;
+} __attribute__((packed)) nr_sdap_dl_hdr_t;
+
+typedef struct nr_sdap_ul_hdr_s {
+  uint8_t QFI:6;
+  uint8_t R:1;
+  uint8_t DC:1;
+} __attribute__((packed)) nr_sdap_ul_hdr_t;
+
+typedef struct nr_sdap_entity_s {
+  uint16_t rnti;
+  nr_pdcp_entity_t *default_drb;
+  int pdusession_id;
+  nr_pdcp_entity_t *qfi2drb_table[SDAP_MAX_QFI];
+
+  void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, uint8_t drb);
+  void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi);
+  nr_pdcp_entity_t *(*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi, long upper_layer_rb_id);
+
+  nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi);
+  nr_pdcp_entity_t *(*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, nr_pdcp_entity_t *pdcp_entity, int map_type, uint8_t dl_qfi);
+  void (*sdap_submit_ctrl_pdu)(int rnti, nr_pdcp_entity_t *sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
+
+
+  boolean_t (*tx_entity)(struct nr_sdap_entity_s *entity,
+                         protocol_ctxt_t *ctxt_p,
+                         const srb_flag_t srb_flag,
+                         const rb_id_t rb_id,
+                         const mui_t mui,
+                         const confirm_t confirm,
+                         const sdu_size_t sdu_buffer_size,
+                         unsigned char *const sdu_buffer,
+                         const pdcp_transmission_mode_t pt_mode,
+                         const uint32_t *sourceL2Id,
+                         const uint32_t *destinationL2Id);
+
+  void (*rx_entity)(struct nr_sdap_entity_s *entity,
+                    nr_pdcp_entity_t *pdcp_entity,
+                    int rnti,
+                    char *buf,
+                    int size);
+
+  /* List of entities */
+  struct nr_sdap_entity_s *next_entity;
+} nr_sdap_entity_t;
+
+/* QFI to DRB Mapping Related Function */
+void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, uint8_t drb);
+
+/* QFI to DRB Mapping Related Function */
+void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi);
+
+/*
+ * TS 37.324
+ * 4.4 Functions
+ * Mapping between a QoS flow and a DRB for both DL and UL.
+ *
+ * 5.2.1 Uplink
+ * If there is no stored QoS flow to DRB mapping rule for the QoS flow as specified in the subclause 5.3, map the SDAP SDU to the default DRB
+ * else, map the SDAP SDU to the DRB according to the stored QoS flow to DRB mapping rule.
+ */
+nr_pdcp_entity_t *nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi, long upper_layer_rb_id);
+
+/*
+ * TS 37.324 5.3 QoS flow to DRB Mapping 
+ * construct an end-marker control PDU, as specified in the subclause 6.2.3, for the QoS flow;
+ */
+nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi);
+
+/*
+ * TS 37.324 5.3 QoS flow to DRB Mapping 
+ * map the end-marker control PDU to the
+ * 1.) default DRB or 
+ * 2.) DRB according to the stored QoS flow to DRB mapping rule
+ */
+nr_pdcp_entity_t *nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, nr_pdcp_entity_t *pdcp_entity, int map_type, uint8_t dl_qfi);
+
+/*
+ * TS 37.324 5.3 QoS flow to DRB Mapping 
+ * Submit the end-marker control PDU to the lower layer.
+ */
+void nr_sdap_submit_ctrl_pdu(int rnti, nr_pdcp_entity_t *sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
+
+/*
+ * TS 37.324 5.3 QoS flow to DRB Mapping 
+ * 5.3.1 Configuration Procedures
+ */
+void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity, 
+                               nr_pdcp_entity_t *pdcp_entity, 
+                               uint16_t rnti,
+                               NR_QFI_t *mapped_qfi_2_add, 
+                               uint8_t mappedQFIs2AddCount,
+                               uint8_t drb_identity);
+
+/*
+ * TS 37.324 4.4 5.1.1 SDAP entity establishment
+ * Establish an SDAP entity.
+ */
+nr_sdap_entity_t *new_nr_sdap_entity(uint16_t rnti,
+                                     int pdusession_id,
+                                     boolean_t is_defaultDRB,
+                                     uint8_t default_DRB,
+                                     NR_QFI_t *mapped_qfi_2_add,
+                                     uint8_t mappedQFIs2AddCount);
+
+/* Entity Handling Related Functions */
+nr_sdap_entity_t *nr_sdap_get_entity(uint16_t rnti, int pdusession_id);
+
+/* Entity Handling Related Functions */
+void delete_nr_sdap_entity(uint16_t rnti);
+
+#endif
diff --git a/openair2/SDAP/nr_sdap/nr_sdap_gnb.c b/openair2/SDAP/nr_sdap/nr_sdap_gnb.c
deleted file mode 100644
index 5f0a2640e96..00000000000
--- a/openair2/SDAP/nr_sdap/nr_sdap_gnb.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-#include "nr_sdap_gnb.h"
-#include <openair2/LAYER2/PDCP_v10.1.0/pdcp.h>
-
-boolean_t sdap_gnb_data_req(protocol_ctxt_t *ctxt_p,
-                            const srb_flag_t srb_flag,
-                            const rb_id_t rb_id,
-                            const mui_t mui,
-                            const confirm_t confirm,
-                            const sdu_size_t sdu_buffer_size,
-                            unsigned char *const sdu_buffer,
-                            const pdcp_transmission_mode_t pt_mode,
-                            const uint32_t *sourceL2Id,
-                            const uint32_t *destinationL2Id
-                           ) {
-  if(sdu_buffer == NULL) {
-    LOG_E(PDCP, "%s:%d:%s: SDAP Layer gNB - NULL sdu_buffer \n", __FILE__, __LINE__, __FUNCTION__);
-    exit(1);
-  }
-
-  if(sdu_buffer_size == 0) {
-    LOG_E(PDCP, "%s:%d:%s: SDAP Layer gNB - NULL or 0 sdu_buffer_size \n", __FILE__, __LINE__, __FUNCTION__);
-    exit(1);
-  }
-
-  uint8_t *sdap_buf = (uint8_t *)malloc(sdu_buffer_size+SDAP_HDR_LENGTH);
-  nr_sdap_dl_hdr_t sdap_hdr;
-  sdap_hdr.RDI = 0; // SDAP_Hardcoded -
-  sdap_hdr.RQI = 0; // SDAP_Hardcoded - Should get this info from DL_PDU_SESSION_INFORMATION
-  sdap_hdr.QFI = 1; // SDAP_Hardcoded - Should get this info from DL_PDU_SESSION_INFORMATION
-  memcpy(&sdap_buf[0], &sdap_hdr, 1);
-  memcpy(&sdap_buf[1], sdu_buffer, sdu_buffer_size);
-  rb_id_t sdap_drb_id = rb_id; // SDAP_Hardcoded - Should get this info from QFI to DRB mapping table
-  boolean_t ret = pdcp_data_req(ctxt_p,
-                                srb_flag,
-                                sdap_drb_id,
-                                mui,
-                                confirm,
-                                sdu_buffer_size+1,
-                                sdap_buf,
-                                pt_mode,
-                                sourceL2Id,
-                                destinationL2Id);
-
-  if(!ret) {
-    LOG_E(PDCP, "%s:%d:%s: SDAP Layer gNB - PDCP DL refused PDU\n", __FILE__, __LINE__, __FUNCTION__);
-    free(sdap_buf);
-    return 0;
-  }
-
-  free(sdap_buf);
-  return 1;
-}
-
-void sdap_gnb_ul_header_handler(char sdap_gnb_ul_hdr) {
-  nr_sdap_ul_hdr_t *sdap_hdr_ul = (nr_sdap_ul_hdr_t *)&sdap_gnb_ul_hdr;
-
-  switch (sdap_hdr_ul->DC) {
-    case SDAP_HDR_UL_DATA_PDU:
-      LOG_I(PDCP, "%s:%d:%s: SDAP Layer gNB - UL Received SDAP Data PDU\n", __FILE__, __LINE__, __FUNCTION__);
-      break;
-
-    case SDAP_HDR_UL_CTRL_PDU:
-      LOG_I(PDCP, "%s:%d:%s: SDAP Layer gNB - Received SDAP Control PDU\n", __FILE__, __LINE__, __FUNCTION__);
-      break;
-  }
-}
\ No newline at end of file
diff --git a/openair2/SDAP/nr_sdap/nr_sdap_gnb.h b/openair2/SDAP/nr_sdap/nr_sdap_gnb.h
deleted file mode 100644
index 243aa890108..00000000000
--- a/openair2/SDAP/nr_sdap/nr_sdap_gnb.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-#ifndef _NR_SDAP_GNB_
-#define _NR_SDAP_GNB_
-
-#include "openair2/COMMON/platform_types.h"
-#include "common/utils/LOG/log.h"
-
-#define SDAP_BITMASK_DC         (0x80)
-#define SDAP_BITMASK_R          (0x40)
-#define SDAP_BITMASK_QFI        (0x3F)
-#define SDAP_HDR_UL_DATA_PDU    (1)
-#define SDAP_HDR_UL_CTRL_PDU    (0)
-#define SDAP_HDR_LENGTH         (1)
-
-typedef struct nr_sdap_dl_hdr_s {
-  uint8_t QFI:6;
-  uint8_t RQI:1;
-  uint8_t RDI:1;
-} __attribute__((packed)) nr_sdap_dl_hdr_t;
-
-typedef struct nr_sdap_ul_hdr_s {
-  uint8_t QFI:6;
-  uint8_t R:1;
-  uint8_t DC:1;
-} __attribute__((packed)) nr_sdap_ul_hdr_t;
-
-boolean_t sdap_gnb_data_req(protocol_ctxt_t *ctxt_p,
-                            const srb_flag_t srb_flag,
-                            const rb_id_t rb_id,
-                            const mui_t mui,
-                            const confirm_t confirm,
-                            const sdu_size_t sdu_buffer_size,
-                            unsigned char *const sdu_buffer,
-                            const pdcp_transmission_mode_t pt_mode,
-                            const uint32_t *sourceL2Id,
-                            const uint32_t *destinationL2Id
-                           );
-
-void sdap_gnb_ul_header_handler(char sdap_gnb_ul_hdr);
-
-#endif
\ No newline at end of file
diff --git a/openair2/SDAP/nr_sdap/sdap_gNB.c b/openair2/SDAP/nr_sdap/sdap_gNB.c
deleted file mode 100644
index ad84e4c273a..00000000000
--- a/openair2/SDAP/nr_sdap/sdap_gNB.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-/*! \file sdap_gNB.c
- * \brief sdap tasks for gNB
- * \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
- * \date 2018
- * \version 1.0
- */
-#define SDAP_GNB
-#define SDAP_GNB_C
-
diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp
index cc41de3550b..3c6c63c6a42 100644
--- a/openair3/ocp-gtpu/gtp_itf.cpp
+++ b/openair3/ocp-gtpu/gtp_itf.cpp
@@ -17,7 +17,7 @@ extern "C" {
 #include <openair2/COMMON/gtpv1_u_messages_types.h>
 #include <openair3/ocp-gtpu/gtp_itf.h>
 #include <openair2/LAYER2/PDCP_v10.1.0/pdcp.h>
-#include "openair2/SDAP/nr_sdap/nr_sdap_gnb.h"
+#include "openair2/SDAP/nr_sdap/nr_sdap.h"
 //#include <openair1/PHY/phy_extern.h>
 
 #pragma pack(1)
@@ -34,8 +34,35 @@ typedef struct Gtpv1uMsgHeader {
   teid_t teid;
 } __attribute__((packed)) Gtpv1uMsgHeaderT;
 
+typedef struct Gtpv1uMsgHeaderOptFields {
+  uint8_t seqNum1Oct;
+  uint8_t seqNum2Oct;
+  uint8_t NPDUNum;
+  uint8_t NextExtHeaderType;    
+} __attribute__((packed)) Gtpv1uMsgHeaderOptFieldsT;
+
+typedef struct PDUSessionContainer {
+  uint8_t spare:4;
+  uint8_t PDU_type:4;
+  uint8_t QFI:6;
+  uint8_t RQI:1;
+  uint8_t PPP:1;
+} __attribute__((packed)) PDUSessionContainerT;
+
+typedef struct Gtpv1uExtHeader {
+  uint8_t ExtHeaderLen;
+  PDUSessionContainerT pdusession_cntr;
+  //uint8_t NextExtHeaderType;
+}__attribute__((packed)) Gtpv1uExtHeaderT;
+
 #pragma pack()
 
+// TS 29.281, fig 5.2.1-3
+#define PDU_SESSION_CONTAINER       (0x85)
+// TS 29.281, 5.2.1
+#define EXT_HDR_LNTH_OCTET_UNITS    (4)
+#define NO_MORE_EXT_HDRS            (0)
+
 // TS 29.060, table 7.1 defines the possible message types
 // here are all the possible messages (3GPP R16)
 #define GTP_ECHO_REQ                                         (1)
@@ -65,6 +92,7 @@ typedef struct {
   rnti_t rnti;
   ebi_t incoming_rb_id;
   gtpCallback callBack;
+  int pdusession_id;
 } rntiData_t;
 
 class gtpEndPoint {
@@ -449,6 +477,8 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer
 
   inst->te2ue_mapping[incoming_teid].callBack=callBack;
 
+  inst->te2ue_mapping[incoming_teid].pdusession_id = (uint8_t)outgoing_bearer_id;
+
   gtpv1u_bearer_t *tmp=&inst->ue2te_mapping[rnti].bearers[outgoing_bearer_id];
 
   int addrs_length_in_bytes = remoteAddr.length / 8;
@@ -574,7 +604,7 @@ int gtpv1u_create_ngu_tunnel(  const instance_t instance,
                                     create_tunnel_req->pdusession_id[i],
                                     create_tunnel_req->outgoing_teid[i],
                                     create_tunnel_req->dst_addr[i], dstport,
-                                    sdap_gnb_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;
@@ -815,10 +845,28 @@ static int Gtpv1uHandleGpdu(int h,
     return GTPNOK;
   }
 
-  int offset=8;
-
-  if( msgHdr->E ||  msgHdr->S ||msgHdr->PN)
-    offset+=8;
+  int offset=sizeof(Gtpv1uMsgHeaderT);
+
+  uint8_t qfi = 0;
+  boolean_t rqi = FALSE;
+
+  if( msgHdr->E || msgHdr->S || msgHdr->PN){
+   Gtpv1uMsgHeaderOptFieldsT *msgHdrOpt = (Gtpv1uMsgHeaderOptFieldsT *)(msgBuf+offset);
+   offset+=sizeof(Gtpv1uMsgHeaderOptFieldsT);
+    if( msgHdr->E && msgHdrOpt->NextExtHeaderType == PDU_SESSION_CONTAINER){
+      Gtpv1uExtHeaderT *msgHdrExt = (Gtpv1uExtHeaderT *)(msgBuf+offset);
+      offset+=msgHdrExt->ExtHeaderLen*EXT_HDR_LNTH_OCTET_UNITS;
+      qfi = msgHdrExt->pdusession_cntr.QFI;
+      rqi = msgHdrExt->pdusession_cntr.RQI;
+
+      /* 
+       * Check if the next extension header type of GTP extension header is set to 0
+       * We can not put it in the struct Gtpv1uExtHeaderT because the length is dynamic.
+       */
+      if(*(msgBuf+offset-1) != NO_MORE_EXT_HDRS)
+        LOG_W(GTPU, "Warning -  Next extension header is not zero, handle it \n");
+    }
+  }
 
   // This context is not good for gtp
   // frame, ... has no meaning
@@ -828,6 +876,9 @@ static int Gtpv1uHandleGpdu(int h,
   ctxt.enb_flag = 1;
   ctxt.instance = inst->addr.originInstance;
   ctxt.rnti = tunnel->second.rnti;
+  ctxt.sdap.qfi = qfi;
+  ctxt.sdap.rqi = rqi;
+  ctxt.sdap.pdusession_id = tunnel->second.pdusession_id;
   ctxt.frame = 0;
   ctxt.subframe = 0;
   ctxt.eNB_index = 0;
-- 
GitLab