diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 721f78eceb..45e5db41e4 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1781,7 +1781,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 5b047c082d..8be3568034 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 1fbf42f62d..89b9c5e94d 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 a8b919e525..b3c06d6be8 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 eaa691d6ef..a289c6d17e 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 c24291de64..67300da308 100644 --- a/openair2/COMMON/platform_types.h +++ b/openair2/COMMON/platform_types.h @@ -233,6 +233,7 @@ 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 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) */ diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 6b41970735..ac70dee092 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -427,6 +427,7 @@ typedef struct NRRrcConfigurationReq_s { bool force_256qam_off; int pusch_TargetSNRx10; int pucch_TargetSNRx10; + bool enable_sdap; } gNB_RrcConfigurationReq; typedef struct NRDuDlReq_s { diff --git a/openair2/F1AP/dummy_enb.c b/openair2/F1AP/dummy_enb.c index d54f9b8df7..9085fdb57c 100644 --- a/openair2/F1AP/dummy_enb.c +++ b/openair2/F1AP/dummy_enb.c @@ -32,16 +32,18 @@ void apply_macrlc_config(gNB_RRC_INST *rrc, abort(); } -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 - ) { +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, + const uint8_t qfi, + const boolean_t rqi, + const int pdusession_id) { abort(); } diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 503e04ecb9..434a2896de 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1192,7 +1192,9 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { LOG_I(RRC, "256 QAM: %s\n", NRRRC_CONFIGURATION_REQ (msg_p).force_256qam_off ? "force off" : "may be on"); NRRRC_CONFIGURATION_REQ (msg_p).scc = scc; NRRRC_CONFIGURATION_REQ (msg_p).scd = scd; - + NRRRC_CONFIGURATION_REQ (msg_p).enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr; + LOG_I(GNB_APP, "SDAP layer is %s\n", NRRRC_CONFIGURATION_REQ (msg_p).enable_sdap ? "enabled" : "disabled"); + }// }//End for (k=0; k configuration, &NRRRC_CONFIGURATION_REQ(msg_p), sizeof(NRRRC_CONFIGURATION_REQ(msg_p))); diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index e1d3d93d0b..eb6b2bdccd 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -125,7 +125,8 @@ typedef enum { #define GNB_CONFIG_STRING_MINRXTXTIME "min_rxtxtime" #define GNB_CONFIG_STRING_ULPRBBLACKLIST "ul_prbblacklist" #define GNB_CONFIG_STRING_FORCE256QAMOFF "force_256qam_off" - +#define GNB_CONFIG_STRING_ENABLE_SDAP "enable_sdap" +#define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n" #define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support" @@ -159,7 +160,8 @@ typedef enum { {GNB_CONFIG_STRING_NRCELLID, NULL, 0, u64ptr:NULL, defint64val:1, TYPE_UINT64, 0}, \ {GNB_CONFIG_STRING_MINRXTXTIME, NULL, 0, iptr:NULL, defintval:2, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, strptr:NULL, defstrval:"", TYPE_STRING, 0}, \ -{GNB_CONFIG_STRING_FORCE256QAMOFF, GNB_CONFIG_HLP_FORCE256QAMOFF, PARAMFLAG_BOOL, iptr:NULL, defintval:0, TYPE_INT, 0} \ +{GNB_CONFIG_STRING_FORCE256QAMOFF, GNB_CONFIG_HLP_FORCE256QAMOFF, PARAMFLAG_BOOL, iptr:NULL, defintval:0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ENABLE_SDAP, GNB_CONFIG_HLP_STRING_ENABLE_SDAP, PARAMFLAG_BOOL, iptr:NULL, defintval:0, TYPE_INT, 0}, \ } #define GNB_GNB_ID_IDX 0 @@ -188,6 +190,7 @@ typedef enum { #define GNB_MINRXTXTIME_IDX 23 #define GNB_ULPRBBLACKLIST_IDX 24 #define GNB_FORCE256QAMOFF_IDX 25 +#define GNB_ENABLE_SDAP_IDX 26 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define GNBPARAMS_CHECK { \ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index d241e43a0f..c20871f6c0 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -373,8 +373,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 fbcc2b96cd..49e9c4142b 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 7d1e2f4931..74ca77a9c5 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -36,7 +36,7 @@ #include "pdcp.h" #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" #include -#include "openair2/SDAP/nr_sdap/nr_sdap_gnb.h" +#include "openair2/SDAP/nr_sdap/nr_sdap.h" #define TODO do { \ printf("%s:%d:%s: todo\n", __FILE__, __LINE__, __FUNCTION__); \ @@ -438,9 +438,13 @@ static void *enb_tun_read_thread(void *_) ctxt.rnti = rnti; - pdcp_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED, + uint8_t qfi = 7; + boolean_t rqi = 0; + int 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); + PDCP_TRANSMISSION_MODE_DATA, NULL, NULL, qfi, rqi, pdusession_id); } return NULL; @@ -481,9 +485,13 @@ static void *ue_tun_read_thread(void *_) ctxt.rnti = rnti; - pdcp_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED, + boolean_t dc = SDAP_HDR_UL_DATA_PDU; + uint8_t qfi = 7; + int 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); + PDCP_TRANSMISSION_MODE_DATA, NULL, NULL, qfi, dc, pdusession_id); } return NULL; @@ -607,28 +615,20 @@ 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->rb_id, + entity->is_gnb, + entity->has_sdap, + entity->has_sdapULheader, + entity->pdusession_id, + ue->rnti, + buf, + size); } else{ for (i = 0; i < 5; i++) { @@ -644,31 +644,16 @@ 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=>PV1U_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(rb_id, + ue->drb[rb_id-1]->is_gnb, + ue->drb[rb_id-1]->has_sdap, + ue->drb[rb_id-1]->has_sdapULheader, + ue->drb[rb_id-1]->pdusession_id, + ue->rnti, + buf, + size); + } } } @@ -967,6 +952,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 { @@ -975,9 +963,13 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s, exit(-1); } pdusession_id = s->cnAssociation->choice.sdap_Config->pdu_Session; - 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; + has_sdap = has_sdapULheader | has_sdapDLheader; + 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 +1001,15 @@ 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(has_sdap, + 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 +1141,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 +1451,10 @@ void nr_pdcp_tick(int frame, int subframe) nr_pdcp_wakeup_timer_thread(nr_pdcp_current_time); } } + +/* + * For the SDAP API + */ +nr_pdcp_ue_manager_t *nr_pdcp_sdap_get_ue_manager(){ + return nr_pdcp_ue_manager; +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c index 160c5ebb22..1f21593c63 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 3a8fc34e20..1715677c6d 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -821,7 +821,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; @@ -872,15 +871,21 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( sdap_config = CALLOC(1, sizeof(NR_SDAP_Config_t)); 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; + if (rrc->configuration.enable_sdap) { + sdap_config->sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present; + sdap_config->sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present; + } else { + sdap_config->sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; + sdap_config->sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; + } 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 0000000000..74ef93aff7 --- /dev/null +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -0,0 +1,86 @@ +/* + * 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, + const uint8_t qfi, + const boolean_t rqi, + const int pdusession_id) { + nr_sdap_entity_t *sdap_entity; + sdap_entity = nr_sdap_get_entity(ctxt_p->rnti, 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, 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, + qfi, + rqi); + return ret; +} + +void sdap_data_ind(rb_id_t pdcp_entity, + int is_gnb, + int has_sdap, + int has_sdapULheader, + int pdusession_id, + int rnti, + char *buf, + int size) { + nr_sdap_entity_t *sdap_entity; + sdap_entity = nr_sdap_get_entity(rnti, 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, + is_gnb, + has_sdap, + has_sdapULheader, + pdusession_id, + 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 0000000000..cd702cfd7f --- /dev/null +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -0,0 +1,66 @@ +/* + * 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, + const uint8_t qfi, + const boolean_t rqi, + const int pdusession_id + ); + +/* + * TS 37.324 4.4 Functions + * Transfer of user plane data + * Uplink - gNB + * Downlink - nrUE + */ +void sdap_data_ind(rb_id_t pdcp_entity, + int is_gnb, + int has_sdap, + int has_sdapULheader, + int pdusession_id, + 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 0000000000..c5d1c1d6fe --- /dev/null +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -0,0 +1,481 @@ +/* + * 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 +#include +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h" + +#include +#include +#include + +typedef struct { + nr_sdap_entity_t *sdap_entity_llist; +} nr_sdap_entity_info; + +static nr_sdap_entity_info sdap_info; + +nr_pdcp_ue_manager_t *nr_pdcp_sdap_get_ue_manager(void); + +void nr_pdcp_submit_sdap_ctrl_pdu(int rnti, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu){ + nr_pdcp_ue_t *ue; + nr_pdcp_ue_manager_t *nr_pdcp_ue_manager; + nr_pdcp_ue_manager = nr_pdcp_sdap_get_ue_manager(); + ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, rnti); + ue->drb[sdap_ctrl_pdu_drb-1]->recv_sdu(ue->drb[sdap_ctrl_pdu_drb-1], (char*)&ctrl_pdu, SDAP_HDR_LENGTH, RLC_MUI_UNDEFINED); + return; +} + +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, + const uint8_t qfi, + const boolean_t rqi + ) { + /* 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]; + rb_id_t pdcp_entity = entity->qfi2drb_map(entity, qfi, rb_id); + + if(pdcp_entity){ + sdap_drb_id = pdcp_entity; + pdcp_ent_has_sdap = entity->qfi2drb_table[qfi].hasSdap; + } + + 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 = qfi; + sdap_hdr.RQI = 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 = qfi; + sdap_hdr.R = 0; + sdap_hdr.DC = rqi; + /* 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, + rb_id_t pdcp_entity, + int is_gnb, + int has_sdap, + int has_sdapHeader, + int pdusession_id, + 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(is_gnb) { // gNB + if(has_sdap && has_sdapHeader ) { // 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(>pu_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 = pdusession_id; + LOG_D(SDAP, "%s() sending message to gtp size %d\n", __func__, size-offset); + itti_send_msg_to_task(TASK_GTPV1_U, 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(has_sdap && has_sdapHeader) { // 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].drb_id && entity->default_drb){ + nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI); + rb_id_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 != entity->qfi2drb_table[sdap_hdr->QFI].drb_id) && + has_sdapHeader ){ + nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI); + rb_id_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].drb_id = pdcp_entity; + } + + /* + * 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, rb_id_t drb, boolean_t hasSdap){ + if(qfi < SDAP_MAX_QFI && + qfi > SDAP_MAP_RULE_EMPTY && + drb > 0 && + drb <= AVLBL_DRB) + { + entity->qfi2drb_table[qfi].drb_id = drb; + entity->qfi2drb_table[qfi].hasSdap = hasSdap; + LOG_D(SDAP, "Updated QFI to DRB Map: QFI %u -> DRB %ld \n", qfi, entity->qfi2drb_table[qfi].drb_id); + LOG_D(SDAP, "DRB %ld %s\n", entity->qfi2drb_table[qfi].drb_id, hasSdap ? "has SDAP" : "does not have SDAP"); + } +} + +void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi){ + entity->qfi2drb_table[qfi].drb_id = SDAP_NO_MAPPING_RULE; + LOG_D(SDAP, "Deleted QFI to DRB Map for QFI %u \n", qfi); +} + +rb_id_t nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t upper_layer_rb_id){ + rb_id_t pdcp_entity; + + pdcp_entity = entity->qfi2drb_table[qfi].drb_id; + + if(pdcp_entity){ + return pdcp_entity; + } else if(entity->default_drb) { + LOG_D(SDAP, "Mapped QFI %u to Default DRB\n", qfi); + return entity->default_drb; + } else { + 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; +} + +rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi){ + rb_id_t drb_of_endmarker = 0; + 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); + 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, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu){ + if(sdap_ctrl_pdu_drb){ + nr_pdcp_submit_sdap_ctrl_pdu(rnti, sdap_ctrl_pdu_drb, ctrl_pdu); + LOG_D(SDAP, "Sent Control PDU to PDCP Layer.\n"); + } +} + +void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity, + rb_id_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].drb_id == SDAP_NO_MAPPING_RULE){ + nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi); + rb_id_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].drb_id != drb_identity && existing_sdap_entity->qfi2drb_table[qfi].hasSdap){ + nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi); + rb_id_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(int has_sdap, + 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); + rb_id_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) { + sdap_entity->default_drb = drb_identity; + LOG_I(SDAP, "Default DRB for the created SDAP entity: %ld \n", sdap_entity->default_drb); + + 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, has_sdap); + } + } + } + + 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 0000000000..b46e5bf4e3 --- /dev/null +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -0,0 +1,182 @@ +/* + * 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 +#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 qfi2drb_s { + rb_id_t drb_id; + boolean_t hasSdap; +} qfi2drb_t; + +void nr_pdcp_submit_sdap_ctrl_pdu(int rnti, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); + +typedef struct nr_sdap_entity_s { + uint16_t rnti; + rb_id_t default_drb; + int pdusession_id; + qfi2drb_t qfi2drb_table[SDAP_MAX_QFI]; + + void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, boolean_t hasSdap); + void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi); + rb_id_t (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t upper_layer_rb_id); + + nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); + rb_id_t (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi); + void (*sdap_submit_ctrl_pdu)(int rnti, rb_id_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, + const uint8_t qfi, + const boolean_t rqi + ); + + void (*rx_entity)(struct nr_sdap_entity_s *entity, + rb_id_t pdcp_entity, + int is_gnb, + int has_sdap, + int has_sdapULheader, + int pdusession_id, + 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, rb_id_t drb, boolean_t hasSdap); + +/* 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. + */ +rb_id_t nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t 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 + */ +rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_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, rb_id_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, + rb_id_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(int has_sdap, + 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 5f0a2640e9..0000000000 --- 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 - -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 243aa89010..0000000000 --- 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 ad84e4c273..0000000000 --- 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 , Cedric Roux , Navid Nikaein - * \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 cc41de3550..7b8ba308bf 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -17,9 +17,11 @@ extern "C" { #include #include #include -#include "openair2/SDAP/nr_sdap/nr_sdap_gnb.h" +#include "openair2/SDAP/nr_sdap/nr_sdap.h" //#include +static boolean_t is_gnb = false; + #pragma pack(1) typedef struct Gtpv1uMsgHeader { @@ -34,8 +36,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 +94,8 @@ typedef struct { rnti_t rnti; ebi_t incoming_rb_id; gtpCallback callBack; + gtpCallbackSDAP callBackSDAP; + int pdusession_id; } rntiData_t; class gtpEndPoint { @@ -448,6 +479,10 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer inst->te2ue_mapping[incoming_teid].incoming_rb_id= incoming_bearer_id; inst->te2ue_mapping[incoming_teid].callBack=callBack; + + inst->te2ue_mapping[incoming_teid].callBackSDAP = sdap_data_req; + + inst->te2ue_mapping[incoming_teid].pdusession_id = (uint8_t)outgoing_bearer_id; gtpv1u_bearer_t *tmp=&inst->ue2te_mapping[rnti].bearers[outgoing_bearer_id]; @@ -567,14 +602,14 @@ int gtpv1u_create_ngu_tunnel( const instance_t instance, 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; 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, - sdap_gnb_data_req); + pdcp_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 +850,28 @@ static int Gtpv1uHandleGpdu(int h, return GTPNOK; } - int offset=8; + int offset=sizeof(Gtpv1uMsgHeaderT); - if( msgHdr->E || msgHdr->S ||msgHdr->PN) - offset+=8; + 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 @@ -843,17 +896,34 @@ static int Gtpv1uHandleGpdu(int h, const uint32_t destinationL2Id=0; pthread_mutex_unlock(&globGtp.gtp_lock); - if ( !tunnel->second.callBack(&ctxt, - srb_flag, - rb_id, - mui, - confirm, - sdu_buffer_size, - sdu_buffer, - mode, - &sourceL2Id, - &destinationL2Id) ) - LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h); + if(is_gnb && qfi){ + if ( !tunnel->second.callBackSDAP(&ctxt, + srb_flag, + rb_id, + mui, + confirm, + sdu_buffer_size, + sdu_buffer, + mode, + &sourceL2Id, + &destinationL2Id, + qfi, + rqi, + tunnel->second.pdusession_id) ) + LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h); + } else { + if ( !tunnel->second.callBack(&ctxt, + srb_flag, + rb_id, + mui, + confirm, + sdu_buffer_size, + sdu_buffer, + mode, + &sourceL2Id, + &destinationL2Id) ) + LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h); + } LOG_D(GTPU,"[%d] Received a %d bytes packet for: teid:%x\n", h, msgBufLen-offset, diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index ba6cf0f8bb..17882ebf1e 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -20,6 +20,21 @@ typedef boolean_t (*gtpCallback)( const uint32_t *sourceL2Id, const uint32_t *destinationL2Id); +typedef boolean_t (*gtpCallbackSDAP)( + protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_sizeP, + unsigned char *const sdu_buffer_pP, + const pdcp_transmission_mode_t modeP, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id, + const uint8_t qfi, + const boolean_t rqi, + const int pdusession_id); + typedef struct openAddr_s { char originHost[HOST_NAME_MAX]; char originService[HOST_NAME_MAX];