From e524cd94825a9eb6a42d4915c80a6c69b1bca144 Mon Sep 17 00:00:00 2001 From: Xue Song <xuesong@cn.fujitsu.com> Date: Tue, 17 Nov 2020 19:03:55 +0900 Subject: [PATCH] Add rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ Add rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP Fix some problems about pdu session setup --- common/ran_context.h | 3 + common/utils/msc/msc.h | 1 + openair2/COMMON/gtpv1_u_messages_def.h | 1 + openair2/COMMON/gtpv1_u_messages_types.h | 24 ++ openair2/COMMON/ngap_messages_types.h | 6 +- openair2/COMMON/platform_types.h | 2 +- openair2/GNB_APP/gnb_config.c | 14 +- openair2/RRC/NR/nr_rrc_defs.h | 12 + openair2/RRC/NR/rrc_gNB.c | 4 + openair2/RRC/NR/rrc_gNB_GTPV1U.c | 49 ++++ openair2/RRC/NR/rrc_gNB_GTPV1U.h | 9 + openair2/RRC/NR/rrc_gNB_NGAP.c | 184 ++++++++++++ openair2/RRC/NR/rrc_gNB_NGAP.h | 14 + openair2/SIMULATION/NR_RRC/itti_sim.c | 2 +- openair3/GTPV1-U/gtpv1u_gNB.c | 342 ++++++++++++++++++++++- openair3/GTPV1-U/gtpv1u_gNB_defs.h | 116 ++++++++ openair3/GTPV1-U/gtpv1u_gNB_task.h | 7 + openair3/NGAP/ngap_gNB_encoder.c | 2 +- openair3/NGAP/ngap_gNB_handlers.c | 30 +- openair3/NGAP/ngap_gNB_nas_procedures.c | 24 +- 20 files changed, 813 insertions(+), 33 deletions(-) create mode 100644 openair3/GTPV1-U/gtpv1u_gNB_defs.h diff --git a/common/ran_context.h b/common/ran_context.h index 8262f5dd55e..3f57c000a09 100644 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -47,6 +47,7 @@ #include "NwGtpv1uMsg.h" #include "NwGtpv1uPrivate.h" #include "gtpv1u_eNB_defs.h" +#include "gtpv1u_gNB_defs.h" #include "PHY/defs_L1_NB_IoT.h" #include "RRC/LTE/defs_NB_IoT.h" @@ -109,6 +110,8 @@ typedef struct { struct gNB_MAC_INST_s **nrmac; /// GTPu descriptor gtpv1u_data_t *gtpv1u_data_g; + /// NR GTPu descriptor + nr_gtpv1u_data_t *nr_gtpv1u_data_g; /// RU descriptors. These describe what each radio unit is supposed to do and contain the necessary functions for fronthaul interfaces struct RU_t_s **ru; /// Mask to indicate fronthaul setup status of RU (hard-limit to 64 RUs) diff --git a/common/utils/msc/msc.h b/common/utils/msc/msc.h index b218d58e3dc..77ff6fd62fb 100644 --- a/common/utils/msc/msc.h +++ b/common/utils/msc/msc.h @@ -54,6 +54,7 @@ typedef enum { MSC_S1AP_ENB, MSC_NGAP_GNB, MSC_GTPU_ENB, + MSC_GTPU_GNB, MSC_GTPU_SGW, MSC_S1AP_MME, MSC_NGAP_AMF, diff --git a/openair2/COMMON/gtpv1_u_messages_def.h b/openair2/COMMON/gtpv1_u_messages_def.h index 1948f1596ad..8531ce16a04 100644 --- a/openair2/COMMON/gtpv1_u_messages_def.h +++ b/openair2/COMMON/gtpv1_u_messages_def.h @@ -30,3 +30,4 @@ MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_dat MESSAGE_DEF(GTPV1U_ENB_END_MARKER_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_req_t, Gtpv1uEndMarkerReq) MESSAGE_DEF(GTPV1U_ENB_END_MARKER_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_ind_t, Gtpv1uEndMarkerInd) MESSAGE_DEF(GTPV1U_ENB_S1_REQ, MESSAGE_PRIORITY_MED, Gtpv1uS1Req, gtpv1uS1Req) +MESSAGE_DEF(GTPV1U_GNB_NG_REQ, MESSAGE_PRIORITY_MED, Gtpv1uNGReq, gtpv1uNGReq) diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index 054f3f37341..360d3e44d48 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -26,6 +26,7 @@ #define GTPV1U_MAX_BEARERS_PER_UE max_val_LTE_DRB_Identity +#define NR_GTPV1U_MAX_BEARERS_PER_UE max_val_NR_DRB_Identity #define GTPV1U_ENB_UPDATE_TUNNEL_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uUpdateTunnelReq #define GTPV1U_ENB_UPDATE_TUNNEL_RESP(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uUpdateTunnelResp @@ -39,6 +40,7 @@ #define GTPV1U_ENB_END_MARKER_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uEndMarkerInd #define GTPV1U_ENB_S1_REQ(mSGpTR) (mSGpTR)->ittiMsg.gtpv1uS1Req +#define GTPV1U_GNB_NG_REQ(mSGpTR) (mSGpTR)->ittiMsg.gtpv1uNGReq #define GTPV1U_ALL_TUNNELS_TEID (teid_t)0xFFFFFFFF @@ -170,4 +172,26 @@ typedef struct { in_addr_t enb_ip_address_for_S1u_S12_S4_up; tcp_udp_port_t enb_port_for_S1u_S12_S4_up; } Gtpv1uS1Req; + +typedef struct { + in_addr_t gnb_ip_address_for_NGu_up; + tcp_udp_port_t gnb_port_for_NGu_up; +} Gtpv1uNGReq; +typedef struct gtpv1u_gnb_create_tunnel_req_s { + rnti_t rnti; + int num_tunnels; + teid_t upf_NGu_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier + pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + transport_layer_addr_t upf_addr[NR_GTPV1U_MAX_BEARERS_PER_UE]; +} gtpv1u_gnb_create_tunnel_req_t; + +typedef struct gtpv1u_gnb_create_tunnel_resp_s { + uint8_t status; ///< Status of S1U endpoint creation (Failed = 0xFF or Success = 0x0) + rnti_t rnti; + int num_tunnels; + teid_t gnb_NGu_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier + pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + transport_layer_addr_t gnb_addr; +} gtpv1u_gnb_create_tunnel_resp_t; + #endif /* GTPV1_U_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index ff55f61ec03..74a68c2dc22 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -263,8 +263,8 @@ typedef struct ngap_transport_layer_addr_s { } while (0) typedef struct pdusession_level_qos_parameter_s { - uint8_t qci; - + uint8_t qfi; + uint64_t fiveQI; ngap_allocation_retention_priority_t allocation_retention_priority; } pdusession_level_qos_parameter_t; @@ -291,7 +291,7 @@ typedef enum pdusession_qosflow_mapping_ind_e{ }pdusession_qosflow_mapping_ind_t; typedef struct pdusession_associate_qosflow_s{ - uint8_t qci; + uint8_t qfi; pdusession_qosflow_mapping_ind_t qos_flow_mapping_ind; }pdusession_associate_qosflow_t; diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h index 75e5b99222f..cb6d3bb6b3b 100644 --- a/openair2/COMMON/platform_types.h +++ b/openair2/COMMON/platform_types.h @@ -222,7 +222,7 @@ typedef enum config_action_e { //----------------------------------------------------------------------------- typedef uint32_t teid_t; // tunnel endpoint identifier typedef uint8_t ebi_t; // eps bearer id - +typedef uint8_t pdusessionid_t; //----------------------------------------------------------------------------- diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 37499d2aa74..7a5763c114a 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -714,19 +714,19 @@ int RCconfig_nr_gtpu(void ) { if (address) { MessageDef *message; - AssertFatal((message = itti_alloc_new_message(TASK_GNB_APP, GTPV1U_ENB_S1_REQ))!=NULL,""); - // IPV4_STR_ADDR_TO_INT_NWBO ( address, RC.gtpv1u_data_g->enb_ip_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" ); - // LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,RC.gtpv1u_data_g->enb_ip_address_for_S1u_S12_S4_up); - if (gnb_mode == 1) { // NSA + AssertFatal((message = itti_alloc_new_message(TASK_GNB_APP, GTPV1U_ENB_S1_REQ))!=NULL,""); + // IPV4_STR_ADDR_TO_INT_NWBO ( address, RC.gtpv1u_data_g->enb_ip_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" ); + // LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,RC.gtpv1u_data_g->enb_ip_address_for_S1u_S12_S4_up); IPV4_STR_ADDR_TO_INT_NWBO (address, GTPV1U_ENB_S1_REQ(message).enb_ip_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" ); LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,GTPV1U_ENB_S1_REQ(message).enb_ip_address_for_S1u_S12_S4_up); GTPV1U_ENB_S1_REQ(message).enb_port_for_S1u_S12_S4_up = gnb_port_for_S1U; } else {// TODO SA - IPV4_STR_ADDR_TO_INT_NWBO (address, GTPV1U_ENB_S1_REQ(message).enb_ip_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR gNB NG_U !\n" ); - LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,GTPV1U_ENB_S1_REQ(message).enb_ip_address_for_S1u_S12_S4_up); - GTPV1U_ENB_S1_REQ(message).enb_port_for_S1u_S12_S4_up = gnb_port_for_NGU; + AssertFatal((message = itti_alloc_new_message(TASK_GNB_APP, GTPV1U_GNB_NG_REQ))!=NULL,""); + IPV4_STR_ADDR_TO_INT_NWBO (address, GTPV1U_GNB_NG_REQ(message).gnb_ip_address_for_NGu_up, "BAD IP ADDRESS FORMAT FOR gNB NG_U !\n" ); + LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,GTPV1U_GNB_NG_REQ(message).gnb_ip_address_for_NGu_up); + GTPV1U_GNB_NG_REQ(message).gnb_port_for_NGu_up = gnb_port_for_NGU; } itti_send_msg_to_task (TASK_GTPV1_U, 0, message); // data model is wrong: gtpu doesn't have enb_id (or module_id) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index acf917bd9aa..c7fb5a2b3eb 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -182,6 +182,13 @@ typedef enum nr_e_rab_satus_e { NR_E_RAB_STATUS_FAILED, } nr_e_rab_status_t; +typedef enum nr_pdu_session_status_e { + NR_PDU_SESSION_STATUS_NEW, + NR_PDU_SESSION_STATUS_DONE, // from the gNB perspective + NR_PDU_SESSION_STATUS_ESTABLISHED, // get the reconfigurationcomplete form UE + NR_PDU_SESSION_STATUS_FAILED, +} nr_pdu_session_status_t; + typedef struct nr_e_rab_param_s { e_rab_t param; uint8_t status; @@ -336,6 +343,8 @@ typedef struct gNB_RRC_UE_s { /* Total number of e_rab already setup in the list */ uint8_t setup_e_rabs; + /* Total number of pdu session already setup in the list */ + uint8_t setup_pdu_sessions; /* Number of pdu session to be setup in the list */ uint8_t nb_of_pdusessions; /* Number of e_rab to be modified in the list */ @@ -351,12 +360,15 @@ typedef struct gNB_RRC_UE_s { uint32_t gnb_gtp_teid[S1AP_MAX_E_RAB]; transport_layer_addr_t gnb_gtp_addrs[S1AP_MAX_E_RAB]; rb_id_t gnb_gtp_ebi[S1AP_MAX_E_RAB]; + rb_id_t gnb_gtp_psi[S1AP_MAX_E_RAB]; uint32_t ul_failure_timer; uint32_t ue_release_timer; uint32_t ue_release_timer_thres; uint32_t ue_release_timer_s1; uint32_t ue_release_timer_thres_s1; + uint32_t ue_release_timer_ng; + uint32_t ue_release_timer_thres_ng; uint32_t ue_release_timer_rrc; uint32_t ue_release_timer_thres_rrc; uint32_t ue_reestablishment_timer; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 13ac60d53c2..a0b9d5cab39 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1369,6 +1369,10 @@ void *rrc_gnb_task(void *args_p) { rrc_gNB_process_NGAP_DOWNLINK_NAS(msg_p, msg_name_p, instance, &rrc_gNB_mui); break; + case NGAP_PDUSESSION_SETUP_REQ: + rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(msg_p, msg_name_p, instance); + break; + /* #if defined(ENABLE_USE_MME) diff --git a/openair2/RRC/NR/rrc_gNB_GTPV1U.c b/openair2/RRC/NR/rrc_gNB_GTPV1U.c index 9ab1bbf43a0..293f9e8b9fc 100644 --- a/openair2/RRC/NR/rrc_gNB_GTPV1U.c +++ b/openair2/RRC/NR/rrc_gNB_GTPV1U.c @@ -92,3 +92,52 @@ rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP( return -1; } } + +int +nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP( + const protocol_ctxt_t *const ctxt_pP, + const gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp_pP, + uint8_t *inde_list +) { + rnti_t rnti; + int i; + struct rrc_gNB_ue_context_s *ue_context_p = NULL; + + if (create_tunnel_resp_pP) { + LOG_D(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" RX CREATE_TUNNEL_RESP num tunnels %u \n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), + create_tunnel_resp_pP->num_tunnels); + rnti = create_tunnel_resp_pP->rnti; + ue_context_p = rrc_gNB_get_ue_context( + RC.nrrrc[ctxt_pP->module_id], + ctxt_pP->rnti); + + for (i = 0; i < create_tunnel_resp_pP->num_tunnels; i++) { + ue_context_p->ue_context.gnb_gtp_teid[inde_list[i]] = create_tunnel_resp_pP->gnb_NGu_teid[i]; + ue_context_p->ue_context.gnb_gtp_addrs[inde_list[i]] = create_tunnel_resp_pP->gnb_addr; + ue_context_p->ue_context.gnb_gtp_psi[inde_list[i]] = create_tunnel_resp_pP->pdusession_id[i]; + LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP tunnel (%u, %u) bearer UE context index %u, msg index %u, id %u, gtp addr len %d \n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), + create_tunnel_resp_pP->gnb_NGu_teid[i], + ue_context_p->ue_context.gnb_gtp_teid[inde_list[i]], + inde_list[i], + i, + create_tunnel_resp_pP->pdusession_id[i], + create_tunnel_resp_pP->gnb_addr.length); + } + + MSC_LOG_RX_MESSAGE( + MSC_RRC_GNB, + MSC_GTPU_GNB, + NULL,0, + MSC_AS_TIME_FMT" CREATE_TUNNEL_RESP RNTI %"PRIx16" ntuns %u psid %u enb-s1u teid %u", + 0,0,rnti, + create_tunnel_resp_pP->num_tunnels, + ue_context_p->ue_context.gnb_gtp_psi[0], + ue_context_p->ue_context.gnb_gtp_teid[0]); + (void)rnti; /* avoid gcc warning "set but not used" */ + return 0; + } else { + return -1; + } +} diff --git a/openair2/RRC/NR/rrc_gNB_GTPV1U.h b/openair2/RRC/NR/rrc_gNB_GTPV1U.h index caff825a7a6..748bd98789d 100644 --- a/openair2/RRC/NR/rrc_gNB_GTPV1U.h +++ b/openair2/RRC/NR/rrc_gNB_GTPV1U.h @@ -37,3 +37,12 @@ rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP( const gtpv1u_enb_create_tunnel_resp_t *const create_tunnel_resp_pP, uint8_t *inde_list ); + +int +nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP( + const protocol_ctxt_t *const ctxt_pP, + const gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp_pP, + uint8_t *inde_list +); + +#endif diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 98b90c301bf..d8dfb921843 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -43,7 +43,9 @@ #include "msc.h" #include "gtpv1u_eNB_task.h" +#include "gtpv1u_gNB_task.h" #include "RRC/LTE/rrc_eNB_GTPV1U.h" +#include "RRC/NR/rrc_gNB_GTPV1U.h" #include "S1AP_NAS-PDU.h" #include "executables/softmodem-common.h" @@ -762,3 +764,185 @@ rrc_gNB_send_NGAP_UPLINK_NAS( LOG_I(NR_RRC,"Send RRC GNB UL Information Transfer \n"); } } + +//------------------------------------------------------------------------------ +void +rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP( + const protocol_ctxt_t *const ctxt_pP, + rrc_gNB_ue_context_t *const ue_context_pP, + uint8_t xid +) +//------------------------------------------------------------------------------ +{ + MessageDef *msg_p; + int pdu_sessions_done = 0; + int pdu_sessions_failed = 0; + int pdusession; + int qos_flow_index; + + msg_p = itti_alloc_new_message (TASK_RRC_GNB, NGAP_PDUSESSION_SETUP_RESP); + NGAP_PDUSESSION_SETUP_RESP(msg_p).gNB_ue_ngap_id = ue_context_pP->ue_context.gNB_ue_ngap_id; + + for (pdusession = 0; pdusession < ue_context_pP->ue_context.setup_pdu_sessions; pdusession++) { + // if (xid == ue_context_pP->ue_context.pdusession[pdusession].xid) { + if (ue_context_pP->ue_context.pdusession[pdusession].status == NR_PDU_SESSION_STATUS_DONE) { + NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].pdusession_id = ue_context_pP->ue_context.pdusession[pdusession].param.pdusession_id; + // NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].pdusession_id = 1; + NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].nb_of_qos_flow = ue_context_pP->ue_context.pdusession[pdusession].param.nb_qos; + NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gtp_teid = ue_context_pP->ue_context.gnb_gtp_teid[pdusession]; + NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.pdu_session_type = PDUSessionType_ipv4; + NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.length = ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].length; + memcpy(NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.buffer, + ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].buffer, sizeof(uint8_t)*20); + for (qos_flow_index = 0; qos_flow_index < NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].nb_of_qos_flow; qos_flow_index++) { + NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = + ue_context_pP->ue_context.pdusession[pdusession].param.qos[qos_flow_index].qfi; + NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; + } + + ue_context_pP->ue_context.pdusession[pdusession].status = NR_PDU_SESSION_STATUS_ESTABLISHED; + LOG_I (NR_RRC,"gnb_gtp_addr (msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d, pdusession_id %d, teid: %u, addr: %d.%d.%d.%d \n ", + pdu_sessions_done, pdusession, ue_context_pP->ue_context.pdusession[pdusession].status, xid, + ue_context_pP->ue_context.nb_of_pdusessions, + NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].pdusession_id, + NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gtp_teid, + NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[0], + NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[1], + NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[2], + NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[3]); + pdu_sessions_done++; + } else if ((ue_context_pP->ue_context.pdusession[pdusession].status == NR_PDU_SESSION_STATUS_NEW) || + (ue_context_pP->ue_context.pdusession[pdusession].status == NR_PDU_SESSION_STATUS_ESTABLISHED)) { + LOG_D (NR_RRC,"PDU-SESSION is NEW or already ESTABLISHED\n"); + } else { /* to be improved */ + ue_context_pP->ue_context.pdusession[pdusession].status = NR_PDU_SESSION_STATUS_FAILED; + NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions_failed[pdu_sessions_failed].pdusession_id = ue_context_pP->ue_context.pdusession[pdusession].param.pdusession_id; + pdu_sessions_failed++; + // TODO add cause when it will be integrated + } + NGAP_PDUSESSION_SETUP_RESP(msg_p).nb_of_pdusessions = pdu_sessions_done; + NGAP_PDUSESSION_SETUP_RESP(msg_p).nb_of_pdusessions_failed = pdu_sessions_failed; + // } else { + // LOG_D(NR_RRC,"xid does not corresponds (context pdu_sessions index %d, status %d, xid %d/%d) \n ", + // pdusession, ue_context_pP->ue_context.pdusession[pdusession].status, xid, ue_context_pP->ue_context.pdusession[pdusession].xid); + // } + } + + if ((pdu_sessions_done > 0) ) { + LOG_I(NR_RRC,"NGAP_PDUSESSION_SETUP_RESP: sending the message: nb_of_pdusessions %d, total pdu_sessions %d, index %d\n", + ue_context_pP->ue_context.nb_of_pdusessions, ue_context_pP->ue_context.setup_pdu_sessions, pdusession); + MSC_LOG_TX_MESSAGE( + MSC_RRC_GNB, + MSC_NGAP_GNB, + (const char *)&NGAP_PDUSESSION_SETUP_RESP (msg_p), + sizeof(ngap_pdusession_setup_resp_t), + MSC_AS_TIME_FMT" PDUSESSION_SETUP_RESP UE %X gNB_ue_ngap_id %u pdu_sessions:%u succ %u fail", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_id_rnti, + NGAP_PDUSESSION_SETUP_RESP (msg_p).gNB_ue_ngap_id, + pdu_sessions_done, pdu_sessions_failed); + itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p); + } + + for(int i = 0; i < NB_RB_MAX; i++) { + ue_context_pP->ue_context.pdusession[i].xid = -1; + } + + return 0; +} + +//------------------------------------------------------------------------------ +int +rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ( + MessageDef *msg_p, + const char *msg_name, + instance_t instance +) +//------------------------------------------------------------------------------ +{ + uint16_t ue_initial_id; + uint32_t gNB_ue_ngap_id; + rrc_gNB_ue_context_t *ue_context_p = NULL; + protocol_ctxt_t ctxt; + gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; + gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp; + uint8_t pdu_sessions_done; + uint8_t inde_list[NR_NB_RB_MAX - 3]= {0}; + int ret = 0; + + ue_initial_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).ue_initial_id; + gNB_ue_ngap_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).gNB_ue_ngap_id; + ue_context_p = rrc_gNB_get_ue_context_from_ngap_ids(instance, ue_initial_id, gNB_ue_ngap_id); + LOG_I(NR_RRC, "[gNB %d] Received %s: ue_initial_id %d, gNB_ue_ngap_id %d \n", + instance, msg_name, ue_initial_id, gNB_ue_ngap_id); + + if (ue_context_p == NULL) { + MessageDef *msg_fail_p = NULL; + LOG_W(NR_RRC, "[gNB %d] In NGAP_PDUSESSION_SETUP_REQ: unknown UE from NGAP ids (%d, %d)\n", instance, ue_initial_id, gNB_ue_ngap_id); + msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, NGAP_PDUSESSION_SETUP_REQUEST_FAIL); + NGAP_PDUSESSION_SETUP_REQ(msg_fail_p).gNB_ue_ngap_id = gNB_ue_ngap_id; + // TODO add failure cause when defined! + itti_send_msg_to_task (TASK_NGAP, instance, msg_fail_p); + return (-1); + } else { + memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); + uint8_t nb_pdusessions_tosetup = NGAP_PDUSESSION_SETUP_REQ(msg_p).nb_pdusessions_tosetup; + pdu_sessions_done = 0; + + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); + for (int i = 0; i < NR_NB_RB_MAX - 3; i++) { + if(ue_context_p->ue_context.pdusession[i].status >= NR_PDU_SESSION_STATUS_DONE) + continue; + ue_context_p->ue_context.pdusession[i].status = NR_PDU_SESSION_STATUS_NEW; + ue_context_p->ue_context.pdusession[i].param = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done]; + create_tunnel_req.pdusession_id[pdu_sessions_done] = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].pdusession_id; + create_tunnel_req.upf_NGu_teid[pdu_sessions_done] = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].gtp_teid; + memcpy(create_tunnel_req.upf_addr[pdu_sessions_done].buffer, + NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[i].upf_addr.buffer, + sizeof(uint8_t)*20); + create_tunnel_req.upf_addr[pdu_sessions_done].length = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[i].upf_addr.length; + LOG_I(NR_RRC,"NGAP PDUSESSION SETUP REQ: local index %d teid %u, pdusession id %d \n", + i, + create_tunnel_req.upf_NGu_teid[i], + create_tunnel_req.pdusession_id[i]); + inde_list[pdu_sessions_done] = i; + pdu_sessions_done++; + + if(pdu_sessions_done >= nb_pdusessions_tosetup) { + break; + } + } + + ue_context_p->ue_context.nb_of_pdusessions = NGAP_PDUSESSION_SETUP_REQ(msg_p).nb_pdusessions_tosetup; + ue_context_p->ue_context.gNB_ue_ngap_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).gNB_ue_ngap_id; + ue_context_p->ue_context.amf_ue_ngap_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).amf_ue_ngap_id; + create_tunnel_req.rnti = ue_context_p->ue_context.rnti; + create_tunnel_req.num_tunnels = pdu_sessions_done; + + ret = gtpv1u_create_ngu_tunnel( + instance, + &create_tunnel_req, + &create_tunnel_resp); + if (ret != 0) { + LOG_E(NR_RRC,"rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ : gtpv1u_create_ngu_tunnel failed,start to release UE %x\n",ue_context_p->ue_context.rnti); + ue_context_p->ue_context.ue_release_timer_ng = 1; + ue_context_p->ue_context.ue_release_timer_thres_ng = 100; + ue_context_p->ue_context.ue_release_timer = 0; + ue_context_p->ue_context.ue_reestablishment_timer = 0; + ue_context_p->ue_context.ul_failure_timer = 20000; // set ul_failure to 20000 for triggering rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ + // rrc_gNB_free_UE(ctxt.module_id,ue_context_p); + ue_context_p->ue_context.ul_failure_timer = 0; + return (0); + } + nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP( + &ctxt, + &create_tunnel_resp, + &inde_list[0]); + ue_context_p->ue_context.setup_pdu_sessions += nb_pdusessions_tosetup; + + // TEST + ue_context_p->ue_context.pdusession[0].status = NR_PDU_SESSION_STATUS_DONE; + rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(&ctxt, ue_context_p, 0); + return(0); + } +} \ No newline at end of file diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.h b/openair2/RRC/NR/rrc_gNB_NGAP.h index d028dc4263d..5224df43729 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.h +++ b/openair2/RRC/NR/rrc_gNB_NGAP.h @@ -93,4 +93,18 @@ rrc_gNB_send_NGAP_UPLINK_NAS( NR_UL_DCCH_Message_t *const ul_dcch_msg ); +void +rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP( + const protocol_ctxt_t *const ctxt_pP, + rrc_gNB_ue_context_t *const ue_context_pP, + uint8_t xid +); + +int +rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ( + MessageDef *msg_p, + const char *msg_name, + instance_t instance +); + #endif diff --git a/openair2/SIMULATION/NR_RRC/itti_sim.c b/openair2/SIMULATION/NR_RRC/itti_sim.c index aab735c1791..f47f07a8185 100644 --- a/openair2/SIMULATION/NR_RRC/itti_sim.c +++ b/openair2/SIMULATION/NR_RRC/itti_sim.c @@ -279,7 +279,7 @@ int create_gNB_tasks(uint32_t gnb_nb) { } } - if (itti_create_task (TASK_GTPV1_U, >pv1u_gNB_task, NULL) < 0) { + if (itti_create_task (TASK_GTPV1_U, &nr_gtpv1u_gNB_task, NULL) < 0) { LOG_E(GTPU, "Create task for GTPV1U failed\n"); return -1; } diff --git a/openair3/GTPV1-U/gtpv1u_gNB.c b/openair3/GTPV1-U/gtpv1u_gNB.c index f13bf137947..8d8a0124374 100644 --- a/openair3/GTPV1-U/gtpv1u_gNB.c +++ b/openair3/GTPV1-U/gtpv1u_gNB.c @@ -38,6 +38,7 @@ #include "NwGtpv1uPrivate.h" #include "NwLog.h" #include "gtpv1u_eNB_defs.h" +#include "gtpv1u_gNB_defs.h" #include "gtpv1_u_messages_types.h" #include "udp_eNB_task.h" #include "common/utils/LOG/log.h" @@ -45,7 +46,6 @@ #include "COMMON/platform_constants.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "common/ran_context.h" -#include "gtpv1u_eNB_defs.h" #include "gtpv1u_eNB_task.h" #include "gtpv1u_gNB_task.h" #include "rrc_eNB_GTPV1U.h" @@ -309,3 +309,343 @@ void *gtpv1u_gNB_task(void *args) { return NULL; } +int nr_gtpv1u_gNB_init(void) { + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uUlpEntityT ulp; + NwGtpv1uUdpEntityT udp; + NwGtpv1uLogMgrEntityT log; + NwGtpv1uTimerMgrEntityT tmr; + // enb_properties_p = enb_config_get()->properties[0]; + RC.nr_gtpv1u_data_g = (nr_gtpv1u_data_t *)calloc(sizeof(nr_gtpv1u_data_t),1); + LOG_I(GTPU, "Initializing GTPU stack %p\n",&RC.nr_gtpv1u_data_g); + + /* Initialize UE hashtable */ + RC.nr_gtpv1u_data_g->ue_mapping = hashtable_create (32, NULL, NULL); + AssertFatal(RC.nr_gtpv1u_data_g->ue_mapping != NULL, " ERROR Initializing TASK_GTPV1_U task interface: in hashtable_create returned %p\n", RC.gtpv1u_data_g->ue_mapping); + RC.nr_gtpv1u_data_g->teid_mapping = hashtable_create (256, NULL, NULL); + AssertFatal(RC.nr_gtpv1u_data_g->teid_mapping != NULL, " ERROR Initializing TASK_GTPV1_U task interface: in hashtable_create\n"); + // RC.gtpv1u_data_g.enb_ip_address_for_S1u_S12_S4_up = enb_properties_p->enb_ipv4_address_for_S1U; + //gtpv1u_data_g.udp_data; + RC.nr_gtpv1u_data_g->seq_num = 0; + RC.nr_gtpv1u_data_g->restart_counter = 0; + + /* Initializing GTPv1-U stack */ + if ((rc = nwGtpv1uInitialize(&RC.nr_gtpv1u_data_g->gtpv1u_stack, GTPU_STACK_ENB)) != NW_GTPV1U_OK) { + LOG_E(GTPU, "Failed to setup nwGtpv1u stack %x\n", rc); + return -1; + } + + if ((rc = nwGtpv1uSetLogLevel(RC.nr_gtpv1u_data_g->gtpv1u_stack, + NW_LOG_LEVEL_DEBG)) != NW_GTPV1U_OK) { + LOG_E(GTPU, "Failed to setup loglevel for stack %x\n", rc); + return -1; + } + + /* Set the ULP API callback. Called once message have been processed by the + * nw-gtpv1u stack. + */ + ulp.ulpReqCallback = gtpv1u_gNB_process_stack_req; + memset((void *)&(ulp.hUlp), 0, sizeof(NwGtpv1uUlpHandleT)); + + if ((rc = nwGtpv1uSetUlpEntity(RC.nr_gtpv1u_data_g->gtpv1u_stack, &ulp)) != NW_GTPV1U_OK) { + LOG_E(GTPU, "nwGtpv1uSetUlpEntity: %x", rc); + return -1; + } + + /* nw-gtpv1u stack requires an udp callback to send data over UDP. + * We provide a wrapper to UDP task. + */ + udp.udpDataReqCallback = gtpv1u_eNB_send_udp_msg; + memset((void *)&(udp.hUdp), 0, sizeof(NwGtpv1uUdpHandleT)); + + if ((rc = nwGtpv1uSetUdpEntity(RC.nr_gtpv1u_data_g->gtpv1u_stack, &udp)) != NW_GTPV1U_OK) { + LOG_E(GTPU, "nwGtpv1uSetUdpEntity: %x", rc); + return -1; + } + + log.logReqCallback = gtpv1u_eNB_log_request; + memset((void *)&(log.logMgrHandle), 0, sizeof(NwGtpv1uLogMgrHandleT)); + + if ((rc = nwGtpv1uSetLogMgrEntity(RC.nr_gtpv1u_data_g->gtpv1u_stack, &log)) != NW_GTPV1U_OK) { + LOG_E(GTPU, "nwGtpv1uSetLogMgrEntity: %x", rc); + return -1; + } + + /* Timer interface is more complicated as both wrappers doesn't send a message + * to the timer task but call the timer API functions start/stop timer. + */ + tmr.tmrMgrHandle = 0; + tmr.tmrStartCallback = gtpv1u_start_timer_wrapper; + tmr.tmrStopCallback = gtpv1u_stop_timer_wrapper; + + if ((rc = nwGtpv1uSetTimerMgrEntity(RC.nr_gtpv1u_data_g->gtpv1u_stack, &tmr)) != NW_GTPV1U_OK) { + LOG_E(GTPU, "nwGtpv1uSetTimerMgrEntity: %x", rc); + return -1; + } + +#if defined(GTP_DUMP_SOCKET) && GTP_DUMP_SOCKET > 0 + + if ((ret = gtpv1u_eNB_create_dump_socket()) < 0) { + return -1; + } + +#endif + LOG_D(GTPU, "Initializing GTPV1U interface for eNB: DONE\n"); + return 0; +} + +//----------------------------------------------------------------------------- +int +gtpv1u_create_ngu_tunnel( + const instance_t instanceP, + const gtpv1u_gnb_create_tunnel_req_t *const create_tunnel_req_pP, + gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp_pP) +{ + /* Create a new nw-gtpv1-u stack req using API */ + NwGtpv1uUlpApiT stack_req; + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + /* Local tunnel end-point identifier */ + teid_t ngu_teid = 0; + nr_gtpv1u_teid_data_t *gtpv1u_teid_data_p = NULL; + nr_gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL; + //MessageDef *message_p = NULL; + hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS; + int i; + pdusessionid_t pdusession_id = 0; + // int ipv4_addr = 0; + int ip_offset = 0; + in_addr_t in_addr; + int addrs_length_in_bytes= 0; + int loop_counter = 0; + int ret = 0; + MSC_LOG_RX_MESSAGE( + MSC_GTPU_GNB, + MSC_RRC_GNB, + NULL,0, + MSC_AS_TIME_FMT" CREATE_TUNNEL_REQ RNTI %"PRIx16" inst %u ntuns %u psid %u upf-ngu teid %u", + 0,0,create_tunnel_req_pP->rnti, instanceP, + create_tunnel_req_pP->num_tunnels, create_tunnel_req_pP->pdusession_id[0], + create_tunnel_req_pP->upf_NGu_teid[0]); + create_tunnel_resp_pP->rnti = create_tunnel_req_pP->rnti; + create_tunnel_resp_pP->status = 0; + create_tunnel_resp_pP->num_tunnels = 0; + + for (i = 0; i < create_tunnel_req_pP->num_tunnels; i++) { + ip_offset = 0; + loop_counter = 0; + pdusession_id = create_tunnel_req_pP->pdusession_id[i]; + LOG_D(GTPU, "Rx GTPV1U_GNB_CREATE_TUNNEL_REQ ue rnti %x pdu session id %u\n", + create_tunnel_req_pP->rnti, pdusession_id); + memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT)); + stack_req.apiType = NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT; + + do { + ngu_teid = gtpv1u_new_teid(); + LOG_D(GTPU, "gtpv1u_create_ngu_tunnel() 0x%x %u(dec)\n", ngu_teid, ngu_teid); + stack_req.apiInfo.createTunnelEndPointInfo.teid = ngu_teid; + stack_req.apiInfo.createTunnelEndPointInfo.hUlpSession = 0; + stack_req.apiInfo.createTunnelEndPointInfo.hStackSession = 0; + rc = nwGtpv1uProcessUlpReq(RC.nr_gtpv1u_data_g->gtpv1u_stack, &stack_req); + LOG_D(GTPU, ".\n"); + loop_counter++; + } while (rc != NW_GTPV1U_OK && loop_counter < 10); + + if ( rc != NW_GTPV1U_OK && loop_counter == 10 ) { + LOG_E(GTPU,"NwGtpv1uCreateTunnelEndPoint failed 10 times,start next loop\n"); + ret = -1; + continue; + } + + //----------------------- + // PDCP->GTPV1U mapping + //----------------------- + hash_rc = hashtable_get(RC.nr_gtpv1u_data_g->ue_mapping, create_tunnel_req_pP->rnti, (void **)>pv1u_ue_data_p); + + if ((hash_rc == HASH_TABLE_KEY_NOT_EXISTS) || (hash_rc == HASH_TABLE_OK)) { + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + gtpv1u_ue_data_p = calloc (1, sizeof(gtpv1u_ue_data_t)); + hash_rc = hashtable_insert(RC.nr_gtpv1u_data_g->ue_mapping, create_tunnel_req_pP->rnti, gtpv1u_ue_data_p); + AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting ue_mapping in GTPV1U hashtable"); + } + + gtpv1u_ue_data_p->ue_id = create_tunnel_req_pP->rnti; + gtpv1u_ue_data_p->instance_id = 0; // TO DO + memcpy(&create_tunnel_resp_pP->gnb_addr.buffer, + &RC.nr_gtpv1u_data_g->gnb_ip_address_for_NGu_up, + sizeof (in_addr_t)); + + LOG_I(GTPU,"Configured GTPu address : %x\n",RC.nr_gtpv1u_data_g->gnb_ip_address_for_NGu_up); + create_tunnel_resp_pP->gnb_addr.length = sizeof (in_addr_t); + addrs_length_in_bytes = create_tunnel_req_pP->upf_addr[i].length / 8; + AssertFatal((addrs_length_in_bytes == 4) || + (addrs_length_in_bytes == 16) || + (addrs_length_in_bytes == 20), + "Bad transport layer address length %d (bits) %d (bytes)", + create_tunnel_req_pP->upf_addr[i].length, addrs_length_in_bytes); + + if ((addrs_length_in_bytes == 4) || + (addrs_length_in_bytes == 20)) { + in_addr = *((in_addr_t *)create_tunnel_req_pP->upf_addr[i].buffer); + ip_offset = 4; + gtpv1u_ue_data_p->bearers[pdusession_id - GTPV1U_BEARER_OFFSET].upf_ip_addr = in_addr; + } + + if ((addrs_length_in_bytes == 16) || + (addrs_length_in_bytes == 20)) { + memcpy(gtpv1u_ue_data_p->bearers[pdusession_id - GTPV1U_BEARER_OFFSET].upf_ip6_addr.s6_addr, + &create_tunnel_req_pP->upf_addr[i].buffer[ip_offset], + 16); + } + + gtpv1u_ue_data_p->bearers[pdusession_id - GTPV1U_BEARER_OFFSET].state = BEARER_IN_CONFIG; + gtpv1u_ue_data_p->bearers[pdusession_id - GTPV1U_BEARER_OFFSET].teid_gNB = ngu_teid; + gtpv1u_ue_data_p->bearers[pdusession_id - GTPV1U_BEARER_OFFSET].teid_gNB_stack_session = stack_req.apiInfo.createTunnelEndPointInfo.hStackSession; + gtpv1u_ue_data_p->bearers[pdusession_id - GTPV1U_BEARER_OFFSET].teid_upf = create_tunnel_req_pP->upf_NGu_teid[i]; + gtpv1u_ue_data_p->num_bearers++; + create_tunnel_resp_pP->gnb_NGu_teid[i] = ngu_teid; + + LOG_I(GTPU,"Copied to create_tunnel_resp tunnel: index %d target gNB ip %d.%d.%d.%d length %d gtp teid %u\n", + i, + create_tunnel_resp_pP->gnb_addr.buffer[0], + create_tunnel_resp_pP->gnb_addr.buffer[1], + create_tunnel_resp_pP->gnb_addr.buffer[2], + create_tunnel_resp_pP->gnb_addr.buffer[3], + create_tunnel_resp_pP->gnb_addr.length, + create_tunnel_resp_pP->gnb_NGu_teid[i]); + } else { + create_tunnel_resp_pP->gnb_NGu_teid[i] = 0; + create_tunnel_resp_pP->status = 0xFF; + } + + create_tunnel_resp_pP->pdusession_id[i] = pdusession_id; + create_tunnel_resp_pP->num_tunnels += 1; + //----------------------- + // GTPV1U->PDCP mapping + //----------------------- + hash_rc = hashtable_get(RC.nr_gtpv1u_data_g->teid_mapping, ngu_teid, (void **)>pv1u_teid_data_p); + + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + gtpv1u_teid_data_p = calloc (1, sizeof(nr_gtpv1u_teid_data_t)); + gtpv1u_teid_data_p->gnb_id = 0; // TO DO + gtpv1u_teid_data_p->ue_id = create_tunnel_req_pP->rnti; + gtpv1u_teid_data_p->pdu_session_id = pdusession_id; + hash_rc = hashtable_insert(RC.nr_gtpv1u_data_g->teid_mapping, ngu_teid, gtpv1u_teid_data_p); + AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting teid mapping in GTPV1U hashtable"); + } else { + create_tunnel_resp_pP->gnb_NGu_teid[i] = 0; + create_tunnel_resp_pP->status = 0xFF; + } + } + + MSC_LOG_TX_MESSAGE( + MSC_GTPU_GNB, + MSC_RRC_GNB, + NULL,0, + "0 GTPV1U_GNB_CREATE_TUNNEL_RESP rnti %x teid %x", + create_tunnel_resp_pP->rnti, + ngu_teid); + LOG_D(GTPU, "Tx GTPV1U_GNB_CREATE_TUNNEL_RESP ue rnti %x status %d\n", + create_tunnel_req_pP->rnti, + create_tunnel_resp_pP->status); + //return 0; + return ret; +} + +//----------------------------------------------------------------------------- +static int gtpv1u_gNB_send_init_udp(const Gtpv1uNGReq *req) { + // Create and alloc new message + MessageDef *message_p; + struct in_addr addr= {0}; + message_p = itti_alloc_new_message(TASK_GTPV1_U, UDP_INIT); + + if (message_p == NULL) { + return -1; + } + + UDP_INIT(message_p).port = req->gnb_port_for_NGu_up; + addr.s_addr = req->gnb_ip_address_for_NGu_up; + UDP_INIT(message_p).address = inet_ntoa(addr); + LOG_I(GTPU, "Tx UDP_INIT IP addr %s (%x)\n", UDP_INIT(message_p).address,UDP_INIT(message_p).port); + MSC_LOG_EVENT( + MSC_GTPU_ENB, + "0 UDP bind %s:%u", + UDP_INIT(message_p).address, + UDP_INIT(message_p).port); + return itti_send_msg_to_task(TASK_UDP, INSTANCE_DEFAULT, message_p); +} + +static int gtpv1u_ng_req( + const instance_t instanceP, + const Gtpv1uNGReq *const req) { + memcpy(&RC.nr_gtpv1u_data_g->gnb_ip_address_for_NGu_up, + &req->gnb_ip_address_for_NGu_up, + sizeof (req->gnb_ip_address_for_NGu_up)); + gtpv1u_gNB_send_init_udp(req); + return 0; +} + +//----------------------------------------------------------------------------- +void *gtpv1u_gNB_process_itti_msg(void *notUsed) { + /* Trying to fetch a message from the message queue. + * If the queue is empty, this function will block till a + * message is sent to the task. + */ + instance_t instance; + MessageDef *received_message_p = NULL; + int rc = 0; + itti_receive_msg(TASK_GTPV1_U, &received_message_p); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_ENB_TASK, VCD_FUNCTION_IN); + DevAssert(received_message_p != NULL); + instance = ITTI_MSG_INSTANCE(received_message_p); + + switch (ITTI_MSG_ID(received_message_p)) { + case GTPV1U_GNB_NG_REQ: + gtpv1u_ng_req(instance, &received_message_p->ittiMsg.gtpv1uNGReq); + break; + + case TERMINATE_MESSAGE: { + if (RC.nr_gtpv1u_data_g->ue_mapping != NULL) { + hashtable_destroy (&(RC.nr_gtpv1u_data_g->ue_mapping)); + } + + if (RC.nr_gtpv1u_data_g->teid_mapping != NULL) { + hashtable_destroy (&(RC.nr_gtpv1u_data_g->teid_mapping)); + } + + LOG_W(GTPU, " *** Exiting GTPU thread\n"); + itti_exit_task(); + } + break; + + case TIMER_HAS_EXPIRED: + nwGtpv1uProcessTimeout(&received_message_p->ittiMsg.timer_has_expired.arg); + break; + + default: { + LOG_E(GTPU, "Unkwnon message ID %d:%s\n", + ITTI_MSG_ID(received_message_p), + ITTI_MSG_NAME(received_message_p)); + } + break; + } + + rc = itti_free(ITTI_MSG_ORIGIN_ID(received_message_p), received_message_p); + AssertFatal(rc == EXIT_SUCCESS, "Failed to free memory (%d)!\n", rc); + received_message_p = NULL; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_ENB_TASK, VCD_FUNCTION_OUT); + return NULL; +} + +void *nr_gtpv1u_gNB_task(void *args) { + int rc = 0; + rc = nr_gtpv1u_gNB_init(); + AssertFatal(rc == 0, "gtpv1u_gNB_init Failed"); + itti_mark_task_ready(TASK_GTPV1_U); + MSC_START_USE(); + + while(1) { + (void) gtpv1u_gNB_process_itti_msg (NULL); + } + + return NULL; +} diff --git a/openair3/GTPV1-U/gtpv1u_gNB_defs.h b/openair3/GTPV1-U/gtpv1u_gNB_defs.h new file mode 100644 index 00000000000..d5c1d876219 --- /dev/null +++ b/openair3/GTPV1-U/gtpv1u_gNB_defs.h @@ -0,0 +1,116 @@ +/* + * 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 rrc_gNB_NGAP.h + * \brief rrc NGAP procedures for gNB + * \author Yoshio INOUE, Masayuki HARADA + * \date 2020 + * \version 0.1 + * \email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com + * (yoshio.inoue%40fujitsu.com%2cmasayuki.harada%40fujitsu.com) + */ + +#include "hashtable.h" +#include "NR_asn_constant.h" + +#ifndef GTPV1U_GNB_DEFS_H_ +#define GTPV1U_GNB_DEFS_H_ + +#include "NwGtpv1u.h" + +#define GTPV1U_UDP_PORT (2152) + +#define NR_GTPV1U_MAX_BEARERS_ID (max_val_NR_DRB_Identity - 3) + +#define GTPV1U_SOURCE_GNB (0) +#define GTPV1U_TARGET_GNB (1) +#define GTPV1U_MSG_FROM_SOURCE_GNB (0) +#define GTPV1U_MSG_FROM_UPF (1) + + +typedef struct nr_gtpv1u_teid_data_s { + /* UE identifier for oaisim stack */ + module_id_t gnb_id; + rnti_t ue_id; + pdusessionid_t pdu_session_id; +} nr_gtpv1u_teid_data_t; + + +typedef struct nr_gtpv1u_bearer_s { + /* TEID used in dl and ul */ + teid_t teid_gNB; ///< gNB TEID + uintptr_t teid_gNB_stack_session; ///< gNB TEID + teid_t teid_upf; ///< Remote TEID + in_addr_t upf_ip_addr; + struct in6_addr upf_ip6_addr; + teid_t teid_tgNB; + in_addr_t tgnb_ip_addr; ///< target gNB ipv4 + struct in6_addr tgnb_ip6_addr; ///< target gNB ipv6 + tcp_udp_port_t port; + //NwGtpv1uStackSessionHandleT stack_session; + bearer_state_t state; +} nr_gtpv1u_bearer_t; + +typedef struct nr_gtpv1u_ue_data_s { + /* UE identifier for oaisim stack */ + rnti_t ue_id; + + /* Unique identifier used between PDCP and GTP-U to distinguish UEs */ + uint32_t instance_id; + int num_bearers; + /* Bearer related data. + * Note that the first LCID available for data is 3 and we fixed the maximum + * number of e-rab per UE to be (32 [id range]), max RB is 11. The real rb id will 3 + rab_id (3..32). + */ + nr_gtpv1u_bearer_t bearers[NR_GTPV1U_MAX_BEARERS_ID]; + + //RB_ENTRY(gtpv1u_ue_data_s) gtpv1u_ue_node; +} nr_gtpv1u_ue_data_t; + +typedef struct nr_gtpv1u_data_s { + /* nwgtpv1u stack internal data */ + NwGtpv1uStackHandleT gtpv1u_stack; + + /* RB tree of UEs */ + hash_table_t *ue_mapping; // PDCP->GTPV1U + hash_table_t *teid_mapping; // GTPV1U -> PDCP + + //RB_HEAD(gtpv1u_ue_map, gtpv1u_ue_data_s) gtpv1u_ue_map_head; + /* Local IP address to use */ + in_addr_t gnb_ip_address_for_NGu_up; + /* UDP internal data */ + //udp_data_t udp_data; + + uint16_t seq_num; + uint8_t restart_counter; + +#ifdef GTPU_IN_KERNEL + char *interface_name; + int interface_index; + + struct iovec *malloc_ring; + void *sock_mmap_ring[16]; + int sock_desc[16]; // indexed by marking +#endif +} nr_gtpv1u_data_t; + + +#endif /* GTPV1U_GNB_DEFS_H_ */ diff --git a/openair3/GTPV1-U/gtpv1u_gNB_task.h b/openair3/GTPV1-U/gtpv1u_gNB_task.h index 42fae7a7149..5e16b0ed0cb 100644 --- a/openair3/GTPV1-U/gtpv1u_gNB_task.h +++ b/openair3/GTPV1-U/gtpv1u_gNB_task.h @@ -32,6 +32,13 @@ int gtpv1u_gNB_init(void); void *gtpv1u_gNB_task(void *args); +void *nr_gtpv1u_gNB_task(void *args); + +int +gtpv1u_create_ngu_tunnel( + const instance_t instanceP, + const gtpv1u_gnb_create_tunnel_req_t * const create_tunnel_req_pP, + gtpv1u_gnb_create_tunnel_resp_t * const create_tunnel_resp_pP); #endif /* GTPV1U_GNB_TASK_H_ */ diff --git a/openair3/NGAP/ngap_gNB_encoder.c b/openair3/NGAP/ngap_gNB_encoder.c index b510dde23e5..c69de324672 100644 --- a/openair3/NGAP/ngap_gNB_encoder.c +++ b/openair3/NGAP/ngap_gNB_encoder.c @@ -73,7 +73,7 @@ int ngap_gNB_encode_pdu(NGAP_NGAP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) { return -1; } - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, pdu); + //ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, pdu); return ret; } diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index c3c487c2f87..6051e917b45 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -49,6 +49,7 @@ #include "assertions.h" #include "conversions.h" #include "msc.h" +#include "NGAP_NonDynamic5QIDescriptor.h" static int ngap_gNB_handle_ng_setup_response(uint32_t assoc_id, @@ -955,7 +956,7 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id, } - dec_rval = uper_decode(NULL, + dec_rval = aper_decode(NULL, &asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, (void **)&pdusessionTransfer_p, item_p->pDUSessionResourceSetupRequestTransfer.buf, @@ -1028,7 +1029,7 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id, qosFlowItem_p = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.array[qosIdx]; /* Set the QOS informations */ - NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).pdusession_param[i].qos[qosIdx].qci = (uint8_t)qosFlowItem_p->qosFlowIdentifier; + NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).pdusession_param[i].qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).pdusession_param[i].qos[qosIdx].allocation_retention_priority.priority_level = qosFlowItem_p->qosFlowLevelQosParameters.allocationAndRetentionPriority.priorityLevelARP; @@ -1289,11 +1290,11 @@ int ngap_gNB_handle_pdusession_setup_request(uint32_t assoc_id, } /* Initial context request = UE-related procedure -> stream != 0 */ - if (stream == 0) { - NGAP_ERROR("[SCTP %d] Received UE-related procedure on stream (%d)\n", - assoc_id, stream); - return -1; - } + // if (stream == 0) { + // NGAP_ERROR("[SCTP %d] Received UE-related procedure on stream (%d)\n", + // assoc_id, stream); + // return -1; + // } ue_desc_p->rx_stream = stream; @@ -1338,7 +1339,7 @@ int ngap_gNB_handle_pdusession_setup_request(uint32_t assoc_id, NGAP_WARN("NAS PDU is not provided, generate a PDUSESSION_SETUP Failure (TBD) back to AMF \n"); } - dec_rval = uper_decode(NULL, + dec_rval = aper_decode(NULL, &asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, (void **)&pdusessionTransfer_p, item_p->pDUSessionResourceSetupRequestTransfer.buf, @@ -1407,8 +1408,13 @@ int ngap_gNB_handle_pdusession_setup_request(uint32_t assoc_id, qosFlowItem_p = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.array[qosIdx]; /* Set the QOS informations */ - NGAP_PDUSESSION_SETUP_REQ(message_p).pdusession_setup_params[i].qos[qosIdx].qci = (uint8_t)qosFlowItem_p->qosFlowIdentifier; - + NGAP_PDUSESSION_SETUP_REQ(message_p).pdusession_setup_params[i].qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; + if(qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics.present == NGAP_QosCharacteristics_PR_nonDynamic5QI){ + if(qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics.choice.nonDynamic5QI != NULL){ + NGAP_PDUSESSION_SETUP_REQ(message_p).pdusession_setup_params[i].qos[qosIdx].fiveQI = + (uint64_t)qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics.choice.nonDynamic5QI->fiveQI; + } + } NGAP_PDUSESSION_SETUP_REQ(message_p).pdusession_setup_params[i].qos[qosIdx].allocation_retention_priority.priority_level = qosFlowItem_p->qosFlowLevelQosParameters.allocationAndRetentionPriority.priorityLevelARP; NGAP_PDUSESSION_SETUP_REQ(message_p).pdusession_setup_params[i].qos[qosIdx].allocation_retention_priority.pre_emp_capability = @@ -1668,7 +1674,7 @@ int ngap_gNB_handle_pdusession_modify_request(uint32_t assoc_id, continue; } - dec_rval = uper_decode(NULL, + dec_rval = aper_decode(NULL, &asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, (void **)&pdusessionTransfer_p, item_p->pDUSessionResourceModifyRequestTransfer.buf, @@ -1709,7 +1715,7 @@ int ngap_gNB_handle_pdusession_modify_request(uint32_t assoc_id, qosFlowItem_p = pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.array[qosIdx]; /* Set the QOS informations */ - NGAP_PDUSESSION_MODIFY_REQ(message_p).pdusession_modify_params[i].qos[qosIdx].qci = (uint8_t)qosFlowItem_p->qosFlowIdentifier; + NGAP_PDUSESSION_MODIFY_REQ(message_p).pdusession_modify_params[i].qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; if(qosFlowItem_p->qosFlowLevelQosParameters) { NGAP_PDUSESSION_MODIFY_REQ(message_p).pdusession_modify_params[i].qos[qosIdx].allocation_retention_priority.priority_level = qosFlowItem_p->qosFlowLevelQosParameters->allocationAndRetentionPriority.priorityLevelARP; diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 250ba46f125..6881bea6752 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -750,7 +750,7 @@ int ngap_gNB_initial_ctxt_resp( ass_qos_item_p = (NGAP_AssociatedQosFlowItem_t *)calloc(1, sizeof(NGAP_AssociatedQosFlowItem_t)); /* qosFlowIdentifier */ - ass_qos_item_p->qosFlowIdentifier = initial_ctxt_resp_p->pdusessions[i].associated_qos_flows[j].qci; + ass_qos_item_p->qosFlowIdentifier = initial_ctxt_resp_p->pdusessions[i].associated_qos_flows[j].qfi; /* qosFlowMappingIndication */ if(initial_ctxt_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind != QOSFLOW_MAPPING_INDICATION_NON) { @@ -1039,6 +1039,8 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, pdusessionTransfer_p = (NGAP_PDUSessionResourceSetupResponseTransfer_t *)calloc(1, sizeof(NGAP_PDUSessionResourceSetupResponseTransfer_t)); pdusessionTransfer_p->dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; + pdusessionTransfer_p->dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel = + calloc(1, sizeof(struct NGAP_GTPTunnel)); GTP_TEID_TO_ASN1(pdusession_setup_resp_p->pdusessions[i].gtp_teid, &pdusessionTransfer_p->dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel->gTP_TEID); @@ -1064,7 +1066,7 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ass_qos_item_p = (NGAP_AssociatedQosFlowItem_t *)calloc(1, sizeof(NGAP_AssociatedQosFlowItem_t)); /* qosFlowIdentifier */ - ass_qos_item_p->qosFlowIdentifier = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qci; + ass_qos_item_p->qosFlowIdentifier = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qfi; /* qosFlowMappingIndication */ if(pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind != QOSFLOW_MAPPING_INDICATION_NON) { @@ -1075,11 +1077,19 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, } memset(&res, 0, sizeof(res)); - res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, pdusessionTransfer_p); - item->pDUSessionResourceSetupResponseTransfer.buf = res.buffer; - item->pDUSessionResourceSetupResponseTransfer.size = res.result.encoded; - - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, pdusessionTransfer_p); +// res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, pdusessionTransfer_p); +// item->pDUSessionResourceSetupResponseTransfer.buf = res.buffer; +// item->pDUSessionResourceSetupResponseTransfer.size = res.result.encoded; + char buffer[100]; + asn_enc_rval_t enc_rval = aper_encode_to_buffer(&asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, + NULL, + pdusessionTransfer_p, + buffer,100); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + item->pDUSessionResourceSetupResponseTransfer.buf = buffer; + item->pDUSessionResourceSetupResponseTransfer.size = enc_rval.encoded; + + //ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, pdusessionTransfer_p); ASN_SEQUENCE_ADD(&ie->value.choice.PDUSessionResourceSetupListSURes.list, item); } -- GitLab