diff --git a/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h b/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h index fbb5062ac..8bf153fc8 100644 --- a/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h @@ -19,11 +19,15 @@ namespace srsenb { class rrc_interface_ngap_nr { public: - virtual int ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key) = 0; - virtual int ue_set_bitrates(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates) = 0; - virtual int ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap_nr::ue_security_cap_s& caps) = 0; - virtual int start_security_mode_procedure(uint16_t rnti) = 0; - virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0; + virtual int ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key) = 0; + virtual int ue_set_bitrates(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates) = 0; + virtual int set_aggregate_max_bitrate(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates) = 0; + virtual int ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap_nr::ue_security_cap_s& caps) = 0; + virtual int start_security_mode_procedure(uint16_t rnti) = 0; + virtual int + establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) = 0; + virtual int allocate_lcid(uint16_t rnti) = 0; + virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0; }; } // namespace srsenb diff --git a/srsenb/hdr/stack/ngap/ngap.h b/srsenb/hdr/stack/ngap/ngap.h index 5e1112b56..87f7415e1 100644 --- a/srsenb/hdr/stack/ngap/ngap.h +++ b/srsenb/hdr/stack/ngap/ngap.h @@ -28,6 +28,7 @@ #include "srsran/common/threads.h" #include "srsran/interfaces/gnb_ngap_interfaces.h" #include "srsran/interfaces/gnb_rrc_nr_interfaces.h" +#include "srsran/interfaces/enb_gtpu_interfaces.h" #include "srsran/srslog/srslog.h" #include #include @@ -42,7 +43,7 @@ public: srslog::basic_logger& logger, srsran::socket_manager_itf* rx_socket_handler); ~ngap(); - int init(const ngap_args_t& args_, rrc_interface_ngap_nr* rrc_); + int init(const ngap_args_t& args_, rrc_interface_ngap_nr* rrc_, gtpu_interface_rrc* gtpu_); void stop(); // RRC NR interface @@ -84,6 +85,7 @@ private: // args rrc_interface_ngap_nr* rrc = nullptr; + gtpu_interface_rrc* gtpu = nullptr; ngap_args_t args = {}; srslog::basic_logger& logger; srsran::task_sched_handle task_sched; diff --git a/srsenb/hdr/stack/ngap/ngap_interfaces.h b/srsenb/hdr/stack/ngap/ngap_interfaces.h index 4740a8c2c..44cd77425 100644 --- a/srsenb/hdr/stack/ngap/ngap_interfaces.h +++ b/srsenb/hdr/stack/ngap/ngap_interfaces.h @@ -13,11 +13,17 @@ #ifndef SRSENB_NGAP_INTERFACES_H #define SRSENB_NGAP_INTERFACES_H +#include "srsran/asn1/ngap_utils.h" + namespace srsenb { class ngap_interface_ngap_proc { public: virtual bool send_initial_ctxt_setup_response() = 0; + virtual bool + send_pdu_session_resource_setup_response(uint16_t pdu_session_id, + uint32_t teid_out, + asn1::bounded_bitstring<1, 160, true, true> transport_layer_address) = 0; }; } // namespace srsenb diff --git a/srsenb/hdr/stack/ngap/ngap_ue.h b/srsenb/hdr/stack/ngap/ngap_ue.h index cbf2550a3..3cf651b91 100644 --- a/srsenb/hdr/stack/ngap/ngap_ue.h +++ b/srsenb/hdr/stack/ngap/ngap_ue.h @@ -13,16 +13,21 @@ #define SRSENB_NGAP_UE_H #include "ngap.h" +#include "ngap_ue_bearer_manager.h" #include "ngap_ue_proc.h" #include "ngap_ue_utils.h" #include "srsran/asn1/asn1_utils.h" #include "srsran/asn1/ngap.h" +#include "srsran/interfaces/enb_gtpu_interfaces.h" namespace srsenb { class ngap::ue : public ngap_interface_ngap_proc { public: - explicit ue(ngap* ngap_ptr_, rrc_interface_ngap_nr* rrc_ptr_, srslog::basic_logger& logger_); + explicit ue(ngap* ngap_ptr_, + rrc_interface_ngap_nr* rrc_ptr_, + gtpu_interface_rrc* gtpu_ptr_, + srslog::basic_logger& logger_); virtual ~ue(); // TS 38.413 - Section 9.2.5.1 - Initial UE Message bool send_initial_ue_message(asn1::ngap_nr::rrcestablishment_cause_e cause, @@ -35,6 +40,10 @@ public: bool send_initial_ctxt_setup_response(); // TS 38.413 - Section 9.2.2.3 - Initial Context Setup Failure bool send_initial_ctxt_setup_failure(asn1::ngap_nr::cause_c cause); + // TS 38.413 - Section 9.2.1.2 - PDU Session Resource Setup Response + bool send_pdu_session_resource_setup_response(uint16_t pdu_session_id, + uint32_t teid_out, + asn1::bounded_bitstring<1, 160, true, true> transport_layer_address); // TS 38.413 - Section 9.2.2.1 - Initial Context Setup Request bool handle_initial_ctxt_setup_request(const asn1::ngap_nr::init_context_setup_request_s& msg); // TS 38.413 - Section 9.2.2.5 - UE Context Release Command @@ -54,7 +63,8 @@ private: ngap* ngap_ptr = nullptr; // state - bool release_requested = false; + bool release_requested = false; + ngap_ue_bearer_manager bearer_manager; // logger srslog::basic_logger& logger; diff --git a/srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h b/srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h new file mode 100644 index 000000000..94031deae --- /dev/null +++ b/srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h @@ -0,0 +1,69 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSENB_NGAP_UE_BEARER_MANAGER_H +#define SRSENB_NGAP_UE_BEARER_MANAGER_H + +#include "srsran/asn1/asn1_utils.h" +#include "srsran/asn1/ngap.h" +#include "srsran/config.h" +#include "srsran/interfaces/enb_gtpu_interfaces.h" +#include "srsran/interfaces/gnb_rrc_nr_interfaces.h" + +namespace srsenb { + +/** + * @brief Manages the GTPU bearers as part of the NGAP session procedures + * */ + +class ngap_ue_bearer_manager +{ +public: + struct pdu_session_t { + struct gtpu_tunnel { + uint32_t teid_out = 0; + uint32_t teid_in = 0; + asn1::bounded_bitstring<1, 160, true, true> address; + }; + uint8_t id = 0; + uint8_t lcid = 0; + asn1::ngap_nr::qos_flow_level_qos_params_s qos_params; + std::vector tunnels; + }; + + ngap_ue_bearer_manager(rrc_interface_ngap_nr* rrc_, gtpu_interface_rrc* gtpu_, srslog::basic_logger& logger_); + ~ngap_ue_bearer_manager(); + + int add_pdu_session(uint16_t rnti, + uint8_t pdu_session_id, + const asn1::ngap_nr::qos_flow_level_qos_params_s& qos, + const asn1::bounded_bitstring<1, 160, true, true>& addr, + uint32_t teid_out, + asn1::ngap_nr::cause_c& cause); + +private: + gtpu_interface_rrc* gtpu = nullptr; + rrc_interface_ngap_nr* rrc = nullptr; + std::map pdu_session_list; + srslog::basic_logger& logger; + + int add_gtpu_bearer(uint16_t rnti, + uint32_t lcid, + uint32_t pdu_session_id, + uint32_t teid_out, + asn1::bounded_bitstring<1, 160, true, true> address, + pdu_session_t::gtpu_tunnel& tunnel, // out parameter + const gtpu_interface_rrc::bearer_props* props = nullptr); + void rem_gtpu_bearer(uint16_t rnti, uint32_t pdu_session_id); +}; +} // namespace srsenb +#endif // SRSENB_NGAP_UE_BEARER_MANAGER_H \ No newline at end of file diff --git a/srsenb/hdr/stack/ngap/ngap_ue_proc.h b/srsenb/hdr/stack/ngap/ngap_ue_proc.h index a549a24d3..71ddd58a0 100644 --- a/srsenb/hdr/stack/ngap/ngap_ue_proc.h +++ b/srsenb/hdr/stack/ngap/ngap_ue_proc.h @@ -21,6 +21,7 @@ #include "srsran/common/buffer_pool.h" #include "srsran/common/stack_procedure.h" #include "srsran/interfaces/gnb_rrc_nr_interfaces.h" +#include "srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h" #include #include @@ -35,7 +36,8 @@ class ngap_ue_initial_context_setup_proc public: explicit ngap_ue_initial_context_setup_proc(ngap_interface_ngap_proc* parent_, rrc_interface_ngap_nr* rrc_, - ngap_ue_ctxt_t* ue_ctxt); + ngap_ue_ctxt_t* ue_ctxt, + srslog::basic_logger& logger_); srsran::proc_outcome_t init(const asn1::ngap_nr::init_context_setup_request_s& msg); srsran::proc_outcome_t react(const bool rrc_reconf_outcome); srsran::proc_outcome_t step(); @@ -54,7 +56,8 @@ class ngap_ue_ue_context_release_proc public: explicit ngap_ue_ue_context_release_proc(ngap_interface_ngap_proc* parent_, rrc_interface_ngap_nr* rrc_, - ngap_ue_ctxt_t* ue_ctxt); + ngap_ue_ctxt_t* ue_ctxt, + srslog::basic_logger& logger_); srsran::proc_outcome_t init(const asn1::ngap_nr::ue_context_release_cmd_s& msg); srsran::proc_outcome_t step(); static const char* name() { return "UE Context Release"; } @@ -70,7 +73,7 @@ private: class ngap_ue_ue_context_modification_proc { public: - explicit ngap_ue_ue_context_modification_proc(ngap_interface_ngap_proc* parent_); + explicit ngap_ue_ue_context_modification_proc(ngap_interface_ngap_proc* parent_, srslog::basic_logger& logger_); srsran::proc_outcome_t init(); srsran::proc_outcome_t step(); static const char* name() { return "UE Context Modification"; } @@ -84,7 +87,9 @@ class ngap_ue_pdu_session_res_setup_proc public: explicit ngap_ue_pdu_session_res_setup_proc(ngap_interface_ngap_proc* parent_, rrc_interface_ngap_nr* rrc_, - ngap_ue_ctxt_t* ue_ctxt); + ngap_ue_ctxt_t* ue_ctxt, + ngap_ue_bearer_manager* bearer_manager, + srslog::basic_logger& logger_); srsran::proc_outcome_t init(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg); srsran::proc_outcome_t step(); static const char* name() { return "UE PDU Session Resource Setup"; } @@ -92,6 +97,7 @@ public: private: ngap_ue_ctxt_t* ue_ctxt; ngap_interface_ngap_proc* parent; + ngap_ue_bearer_manager* bearer_manager; rrc_interface_ngap_nr* rrc = nullptr; srslog::basic_logger& logger; }; diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index 2b5c9932e..1531be0c9 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -90,7 +90,10 @@ public: int ue_set_bitrates(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates); int ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap_nr::ue_security_cap_s& caps); int start_security_mode_procedure(uint16_t rnti); + int establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid); void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu); + int set_aggregate_max_bitrate(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates); + int allocate_lcid(uint16_t rnti); class ue { diff --git a/srsenb/src/stack/ngap/CMakeLists.txt b/srsenb/src/stack/ngap/CMakeLists.txt index 099260995..d5654ae32 100644 --- a/srsenb/src/stack/ngap/CMakeLists.txt +++ b/srsenb/src/stack/ngap/CMakeLists.txt @@ -6,5 +6,5 @@ # the distribution. # -set(SOURCES ngap.cc ngap_ue.cc ngap_ue_proc.cc) +set(SOURCES ngap.cc ngap_ue.cc ngap_ue_proc.cc ngap_ue_bearer_manager.cc) add_library(srsgnb_ngap STATIC ${SOURCES}) diff --git a/srsenb/src/stack/ngap/ngap.cc b/srsenb/src/stack/ngap/ngap.cc index 9d99e8d3a..e3660d749 100644 --- a/srsenb/src/stack/ngap/ngap.cc +++ b/srsenb/src/stack/ngap/ngap.cc @@ -21,6 +21,13 @@ using srsran::uint32_to_uint8; #define procWarning(fmt, ...) ngap_ptr->logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) #define procInfo(fmt, ...) ngap_ptr->logger.info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) +#define WarnUnsupportFeature(cond, featurename) \ + do { \ + if (cond) { \ + logger.warning("Not handling feature - %s", featurename); \ + } \ + } while (0) + using namespace asn1::ngap_nr; namespace srsenb { @@ -105,10 +112,11 @@ ngap::ngap(srsran::task_sched_handle task_sched_, ngap::~ngap() {} -int ngap::init(const ngap_args_t& args_, rrc_interface_ngap_nr* rrc_) +int ngap::init(const ngap_args_t& args_, rrc_interface_ngap_nr* rrc_, gtpu_interface_rrc * gtpu_) { rrc = rrc_; args = args_; + gtpu = gtpu_; build_tai_cgi(); @@ -207,7 +215,7 @@ void ngap::initial_ue(uint16_t rnti, asn1::ngap_nr::rrcestablishment_cause_e cause, srsran::unique_byte_buffer_t pdu) { - std::unique_ptr ue_ptr{new ue{this, rrc, logger}}; + std::unique_ptr ue_ptr{new ue{this, rrc, gtpu, logger}}; ue_ptr->ctxt.rnti = rnti; ue_ptr->ctxt.gnb_cc_idx = gnb_cc_idx; ue* u = users.add_user(std::move(ue_ptr)); @@ -224,7 +232,7 @@ void ngap::initial_ue(uint16_t rnti, srsran::unique_byte_buffer_t pdu, uint32_t s_tmsi) { - std::unique_ptr ue_ptr{new ue{this, rrc, logger}}; + std::unique_ptr ue_ptr{new ue{this, rrc, gtpu, logger}}; ue_ptr->ctxt.rnti = rnti; ue_ptr->ctxt.gnb_cc_idx = gnb_cc_idx; ue* u = users.add_user(std::move(ue_ptr)); @@ -536,6 +544,7 @@ bool ngap::handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cm bool ngap::handle_ue_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg) { + ue* u = handle_ngapmsg_ue_id(msg.protocol_ies.ran_ue_ngap_id.value.value, msg.protocol_ies.amf_ue_ngap_id.value.value); if (u == nullptr) { @@ -543,7 +552,11 @@ bool ngap::handle_ue_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_sess return false; } + if (msg.protocol_ies.ue_aggregate_maximum_bit_rate_present) { + rrc->set_aggregate_max_bitrate(u->ctxt.rnti, msg.protocol_ies.ue_aggregate_maximum_bit_rate.value); + } u->handle_pdu_session_res_setup_request(msg); + return true; } diff --git a/srsenb/src/stack/ngap/ngap_ue.cc b/srsenb/src/stack/ngap/ngap_ue.cc index 26a115c10..01ee89c5e 100644 --- a/srsenb/src/stack/ngap/ngap_ue.cc +++ b/srsenb/src/stack/ngap/ngap_ue.cc @@ -23,12 +23,16 @@ namespace srsenb { /* ngap_ptr::ue Class ********************************************************************************/ -ngap::ue::ue(ngap* ngap_ptr_, rrc_interface_ngap_nr* rrc_ptr_, srslog::basic_logger& logger_) : +ngap::ue::ue(ngap* ngap_ptr_, + rrc_interface_ngap_nr* rrc_ptr_, + gtpu_interface_rrc* gtpu_ptr_, + srslog::basic_logger& logger_) : logger(logger_), ngap_ptr(ngap_ptr_), - initial_context_setup_proc(this, rrc_ptr_, &ctxt), - ue_context_release_proc(this, rrc_ptr_, &ctxt), - ue_pdu_session_res_setup_proc(this, rrc_ptr_, &ctxt) + bearer_manager(rrc_ptr_, gtpu_ptr_, logger_), + initial_context_setup_proc(this, rrc_ptr_, &ctxt, logger_), + ue_context_release_proc(this, rrc_ptr_, &ctxt, logger_), + ue_pdu_session_res_setup_proc(this, rrc_ptr_, &ctxt, &bearer_manager, logger_) { ctxt.ran_ue_ngap_id = ngap_ptr->next_gnb_ue_ngap_id++; gettimeofday(&ctxt.init_timestamp, nullptr); @@ -180,6 +184,46 @@ bool ngap::ue::send_initial_ctxt_setup_failure(cause_c cause) return true; } +bool ngap::ue::send_pdu_session_resource_setup_response( + uint16_t pdu_session_id, + uint32_t teid_out, + asn1::bounded_bitstring<1, 160, true, true> transport_layer_address) +{ + if (not ngap_ptr->amf_connected) { + logger.warning("AMF not connected"); + return false; + } + // TODO: QOS Params + ngap_pdu_c tx_pdu; + tx_pdu.set_successful_outcome().load_info_obj(ASN1_NGAP_NR_ID_PDU_SESSION_RES_SETUP); + pdu_session_res_setup_resp_s& container = tx_pdu.successful_outcome().value.pdu_session_res_setup_resp(); + container.protocol_ies.amf_ue_ngap_id.value = ctxt.amf_ue_ngap_id.value(); + container.protocol_ies.ran_ue_ngap_id.value = ctxt.ran_ue_ngap_id; + container.protocol_ies.pdu_session_res_setup_list_su_res_present = true; + pdu_session_res_setup_item_su_res_s su_res; + su_res.pdu_session_res_setup_resp_transfer.resize(512); + su_res.pdu_session_id = pdu_session_id; + pdu_session_res_setup_resp_transfer_s resp_transfer; + + gtp_tunnel_s& gtp_tunnel = resp_transfer.dlqos_flow_per_tnl_info.uptransport_layer_info.set_gtp_tunnel(); + + gtp_tunnel.gtp_teid.from_number(teid_out); + gtp_tunnel.transport_layer_address = transport_layer_address; + asn1::ngap_nr::associated_qos_flow_list_l qos_flow_list; + asn1::ngap_nr::associated_qos_flow_item_s qos_flow_item; + qos_flow_item.qos_flow_id = 1; + qos_flow_list.push_back(qos_flow_item); + resp_transfer.dlqos_flow_per_tnl_info.associated_qos_flow_list = qos_flow_list; + + asn1::bit_ref bref(su_res.pdu_session_res_setup_resp_transfer.data(), + su_res.pdu_session_res_setup_resp_transfer.size()); + resp_transfer.pack(bref); + su_res.pdu_session_res_setup_resp_transfer.resize(bref.distance_bytes()); + + container.protocol_ies.pdu_session_res_setup_list_su_res.value.push_back(su_res); + return ngap_ptr->sctp_send_ngap_pdu(tx_pdu, ctxt.rnti, "PDUSessionResourceSetupResponse"); +} + /******************************************************************************* /* NGAP message handler ********************************************************************************/ diff --git a/srsenb/src/stack/ngap/ngap_ue_bearer_manager.cc b/srsenb/src/stack/ngap/ngap_ue_bearer_manager.cc new file mode 100644 index 000000000..040ff341d --- /dev/null +++ b/srsenb/src/stack/ngap/ngap_ue_bearer_manager.cc @@ -0,0 +1,93 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h" + +namespace srsenb { +ngap_ue_bearer_manager::ngap_ue_bearer_manager(rrc_interface_ngap_nr* rrc_, + gtpu_interface_rrc* gtpu_, + srslog::basic_logger& logger_) : + gtpu(gtpu_), rrc(rrc_), logger(logger_) +{} +ngap_ue_bearer_manager::~ngap_ue_bearer_manager(){}; + +int ngap_ue_bearer_manager::add_pdu_session(uint16_t rnti, + uint8_t pdu_session_id, + const asn1::ngap_nr::qos_flow_level_qos_params_s& qos, + const asn1::bounded_bitstring<1, 160, true, true>& addr, + uint32_t teid_out, + asn1::ngap_nr::cause_c& cause) +{ + // RRC call for QoS parameter and lcid <-> ID mapping + int lcid = rrc->allocate_lcid(rnti); + + // Only add session if gtpu was successful + pdu_session_t::gtpu_tunnel tunnel; + + if (addr.length() > 32) { + logger.error("Only addresses with length <= 32 (IPv4) are supported"); + cause.set_radio_network().value = asn1::ngap_nr::cause_radio_network_opts::invalid_qos_combination; + return SRSRAN_ERROR; + } + + // TODO long term remove lcid and just use pdu_session_id and rnti as id for GTP tunnel + + int rtn = add_gtpu_bearer(rnti, lcid, pdu_session_id, teid_out, addr, tunnel); + if (rtn != SRSRAN_SUCCESS) { + logger.error("Adding PDU Session ID=%d to GTPU", pdu_session_id); + return SRSRAN_ERROR; + } + + pdu_session_list[pdu_session_id].id = pdu_session_id; + pdu_session_list[pdu_session_id].lcid = lcid; + pdu_session_list[pdu_session_id].qos_params = qos; + pdu_session_list[pdu_session_id].tunnels.push_back(tunnel); + return SRSRAN_SUCCESS; +} + +int ngap_ue_bearer_manager::add_gtpu_bearer(uint16_t rnti, + uint32_t lcid, + uint32_t pdu_session_id, + uint32_t teid_out, + asn1::bounded_bitstring<1, 160, true, true> address, + pdu_session_t::gtpu_tunnel& tunnel, + const gtpu_interface_rrc::bearer_props* props) +{ + // Initialize ERAB tunnel in GTPU right-away. DRBs are only created during RRC setup/reconf + srsran::expected rtn = gtpu->add_bearer(rnti, lcid, address.to_number(), teid_out, props); + if (rtn.is_error()) { + logger.error("Failed adding pdu_session_id=%d to GTPU", pdu_session_id); + return SRSRAN_ERROR; + } + tunnel.teid_out = teid_out; + tunnel.address = address; + tunnel.teid_in = rtn.value(); + + logger.info("Added GTPU tunnel for rnti %x, lcid %d, pdu_session_id=%d, address %s", + rnti, + lcid, + pdu_session_id, + address.to_string()); + return SRSRAN_SUCCESS; +} + +void ngap_ue_bearer_manager::rem_gtpu_bearer(uint16_t rnti, uint32_t pdu_session_id) +{ + auto it = pdu_session_list.find(pdu_session_id); + if (it == pdu_session_list.end()) { + logger.warning("Removing pdu_session=%d from GTPU", pdu_session_id); + return; + } + gtpu->rem_bearer(rnti, it->second.lcid); +} + +} // namespace srsenb \ No newline at end of file diff --git a/srsenb/src/stack/ngap/ngap_ue_proc.cc b/srsenb/src/stack/ngap/ngap_ue_proc.cc index 739698d84..bf9aeac2e 100644 --- a/srsenb/src/stack/ngap/ngap_ue_proc.cc +++ b/srsenb/src/stack/ngap/ngap_ue_proc.cc @@ -18,13 +18,9 @@ namespace srsenb { ngap_ue_initial_context_setup_proc::ngap_ue_initial_context_setup_proc(ngap_interface_ngap_proc* parent_, rrc_interface_ngap_nr* rrc_, - ngap_ue_ctxt_t* ue_ctxt_) : - logger(srslog::fetch_basic_logger("NGAP UE")) -{ - parent = parent_; - rrc = rrc_; - ue_ctxt = ue_ctxt_; -}; + ngap_ue_ctxt_t* ue_ctxt_, + srslog::basic_logger& logger_) : + logger(logger_), parent(parent_), rrc(rrc_), ue_ctxt(ue_ctxt_){}; proc_outcome_t ngap_ue_initial_context_setup_proc::init(const asn1::ngap_nr::init_context_setup_request_s& msg) { @@ -69,8 +65,9 @@ proc_outcome_t ngap_ue_initial_context_setup_proc::step() ngap_ue_ue_context_release_proc::ngap_ue_ue_context_release_proc(ngap_interface_ngap_proc* parent_, rrc_interface_ngap_nr* rrc_, - ngap_ue_ctxt_t* ue_ctxt_) : - logger(srslog::fetch_basic_logger("NGAP UE")) + ngap_ue_ctxt_t* ue_ctxt_, + srslog::basic_logger& logger_) : + logger(logger_) { parent = parent_; rrc = rrc_; @@ -81,6 +78,7 @@ proc_outcome_t ngap_ue_ue_context_release_proc::init(const asn1::ngap_nr::ue_con { // ue_ngap_ids_c ue_ngap_ids = msg.protocol_ies.ue_ngap_ids.value; // cause_c cause = msg.protocol_ies.cause.value; + logger.info("Started %s", name()); return proc_outcome_t::success; } @@ -91,33 +89,81 @@ proc_outcome_t ngap_ue_ue_context_release_proc::step() ngap_ue_pdu_session_res_setup_proc::ngap_ue_pdu_session_res_setup_proc(ngap_interface_ngap_proc* parent_, rrc_interface_ngap_nr* rrc_, - ngap_ue_ctxt_t* ue_ctxt_) : - logger(srslog::fetch_basic_logger("NGAP UE")) -{ - parent = parent_; - rrc = rrc_; - ue_ctxt = ue_ctxt_; -} + ngap_ue_ctxt_t* ue_ctxt_, + ngap_ue_bearer_manager* bearer_manager_, + srslog::basic_logger& logger_) : + parent(parent_), rrc(rrc_), ue_ctxt(ue_ctxt_), bearer_manager(bearer_manager_), logger(logger_) +{} proc_outcome_t ngap_ue_pdu_session_res_setup_proc::init(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg) { if (msg.protocol_ies.pdu_session_res_setup_list_su_req.value.size() != 1) { - logger.error("Not handling multiple su requests"); + logger.error("Not handling zero or multiple su requests"); return proc_outcome_t::error; } + asn1::ngap_nr::pdu_session_res_setup_item_su_req_s su_req = msg.protocol_ies.pdu_session_res_setup_list_su_req.value[0]; + asn1::cbit_ref pdu_session_bref(su_req.pdu_session_res_setup_request_transfer.data(), + su_req.pdu_session_res_setup_request_transfer.size()); + + asn1::ngap_nr::pdu_session_res_setup_request_transfer_s pdu_ses_res_setup_req_trans; + + if (pdu_ses_res_setup_req_trans.unpack(pdu_session_bref) != SRSRAN_SUCCESS) { + logger.error("Unable to unpack PDU session response setup request"); + return proc_outcome_t::error; + } + + if (pdu_ses_res_setup_req_trans.protocol_ies.qos_flow_setup_request_list.value.size() != 1) { + logger.error("Expected one item in QoS flow setup request list"); + return proc_outcome_t::error; + } + + if (pdu_ses_res_setup_req_trans.protocol_ies.ul_ngu_up_tnl_info.value.type() != + asn1::ngap_nr::up_transport_layer_info_c::types::gtp_tunnel) { + logger.error("Expected GTP Tunnel"); + return proc_outcome_t::error; + } + asn1::ngap_nr::qos_flow_setup_request_item_s qos_flow_setup = + pdu_ses_res_setup_req_trans.protocol_ies.qos_flow_setup_request_list.value[0]; + srsran::const_span nas_pdu_dummy; + asn1::ngap_nr::cause_c cause; + uint32_t teid_out = 0; + int lcid; + + teid_out |= pdu_ses_res_setup_req_trans.protocol_ies.ul_ngu_up_tnl_info.value.gtp_tunnel().gtp_teid[0] << 24u; + teid_out |= pdu_ses_res_setup_req_trans.protocol_ies.ul_ngu_up_tnl_info.value.gtp_tunnel().gtp_teid[1] << 16u; + teid_out |= pdu_ses_res_setup_req_trans.protocol_ies.ul_ngu_up_tnl_info.value.gtp_tunnel().gtp_teid[2] << 8u; + teid_out |= pdu_ses_res_setup_req_trans.protocol_ies.ul_ngu_up_tnl_info.value.gtp_tunnel().gtp_teid[3]; + + // TODO: Check cause + + if (bearer_manager->add_pdu_session( + ue_ctxt->rnti, + su_req.pdu_session_id, + qos_flow_setup.qos_flow_level_qos_params, + pdu_ses_res_setup_req_trans.protocol_ies.ul_ngu_up_tnl_info.value.gtp_tunnel().transport_layer_address, + teid_out, + cause) != SRSRAN_SUCCESS) { + logger.warning("Failed to add pdu session\n"); + return proc_outcome_t::error; + } + + // QoS parameter mapping in config in LTE enb + // Transport Layer Address required by the procedure for the reponse + asn1::bounded_bitstring<1, 160, true, true> transport_layer_address; + transport_layer_address = + pdu_ses_res_setup_req_trans.protocol_ies.ul_ngu_up_tnl_info.value.gtp_tunnel().transport_layer_address; if (su_req.pdu_session_nas_pdu_present) { - srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer(); - if (pdu == nullptr) { - logger.error("Fatal Error: Couldn't allocate buffer in ngap_ue_initial_context_setup_proc::init()."); - return proc_outcome_t::error; + lcid = rrc->allocate_lcid(ue_ctxt->rnti); + if (rrc->establish_rrc_bearer(ue_ctxt->rnti, su_req.pdu_session_id, su_req.pdu_session_nas_pdu, lcid) == + SRSRAN_SUCCESS) { + parent->send_pdu_session_resource_setup_response(su_req.pdu_session_id, teid_out, transport_layer_address); + return proc_outcome_t::success; } - memcpy(pdu->msg, su_req.pdu_session_nas_pdu.data(), su_req.pdu_session_nas_pdu.size()); - pdu->N_bytes = su_req.pdu_session_nas_pdu.size(); - rrc->write_dl_info(ue_ctxt->rnti, std::move(pdu)); } + return proc_outcome_t::yield; } diff --git a/srsenb/src/stack/rrc/rrc_nr.cc b/srsenb/src/stack/rrc/rrc_nr.cc index 535f8a62e..7a41bace4 100644 --- a/srsenb/src/stack/rrc/rrc_nr.cc +++ b/srsenb/src/stack/rrc/rrc_nr.cc @@ -390,6 +390,10 @@ int rrc_nr::ue_set_bitrates(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_max { return SRSRAN_SUCCESS; } +int rrc_nr::set_aggregate_max_bitrate(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates) +{ + return SRSRAN_SUCCESS; +} int rrc_nr::ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap_nr::ue_security_cap_s& caps) { return SRSRAN_SUCCESS; @@ -398,6 +402,16 @@ int rrc_nr::start_security_mode_procedure(uint16_t rnti) { return SRSRAN_SUCCESS; } +int rrc_nr::establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) +{ + return SRSRAN_SUCCESS; +} + +int rrc_nr::allocate_lcid(uint16_t rnti) +{ + return SRSRAN_SUCCESS; +} + void rrc_nr::write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) {} /******************************************************************************* diff --git a/srsenb/test/ngap/ngap_test.cc b/srsenb/test/ngap/ngap_test.cc index 834990974..117ace1bb 100644 --- a/srsenb/test/ngap/ngap_test.cc +++ b/srsenb/test/ngap/ngap_test.cc @@ -73,11 +73,20 @@ public: { return SRSRAN_SUCCESS; } + int set_aggregate_max_bitrate(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates) + { + return SRSRAN_SUCCESS; + } int ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap_nr::ue_security_cap_s& caps) { return SRSRAN_SUCCESS; } - int start_security_mode_procedure(uint16_t rnti) { return SRSRAN_SUCCESS; } + int start_security_mode_procedure(uint16_t rnti) { return SRSRAN_SUCCESS; } + int establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) + { + return SRSRAN_SUCCESS; + } + int allocate_lcid(uint16_t rnti) { return SRSRAN_SUCCESS; } void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) {} }; struct dummy_socket_manager : public srsran::socket_manager_itf { @@ -162,8 +171,9 @@ int main(int argc, char** argv) args.amf_addr = "127.0.0.1"; args.gnb_name = "srsgnb01"; - rrc_nr_dummy rrc; - ngap_obj.init(args, &rrc); + rrc_nr_dummy rrc; + gtpu_interface_rrc* gtpu = nullptr; + ngap_obj.init(args, &rrc, gtpu); // Start the log backend. srsran::test_init(argc, argv); diff --git a/srsue/hdr/stack/upper/nas_5g.h b/srsue/hdr/stack/upper/nas_5g.h index 4e68275e9..27ebc2141 100644 --- a/srsue/hdr/stack/upper/nas_5g.h +++ b/srsue/hdr/stack/upper/nas_5g.h @@ -118,6 +118,9 @@ private: srsran::proc_t registration_proc; srsran::proc_t pdu_session_establishment_proc; + // Network information + srsran::nas_5g::network_name_t full_network_name; + // Message sender int send_registration_request(); int send_authentication_response(const uint8_t res[16]); @@ -146,6 +149,7 @@ private: srsran::nas_5g::deregistration_accept_ue_terminated_t& deregistration_accept_ue_terminated); int handle_deregistration_request_ue_terminated( srsran::nas_5g::deregistration_request_ue_terminated_t& deregistration_request_ue_terminated); + int handle_configuration_update_command(srsran::nas_5g::configuration_update_command_t& configuration_update_command); int handle_dl_nas_transport(srsran::nas_5g::dl_nas_transport_t& dl_nas_transport); // message handler container diff --git a/srsue/src/stack/upper/nas_5g.cc b/srsue/src/stack/upper/nas_5g.cc index c6a66bfcd..660b87600 100644 --- a/srsue/src/stack/upper/nas_5g.cc +++ b/srsue/src/stack/upper/nas_5g.cc @@ -581,7 +581,7 @@ int nas_5g::send_pdu_session_establishment_request(uint32_t tran pdu->N_bytes - SEQ_5G_OFFSET, &pdu->msg[MAC_5G_OFFSET]); - logger.info("Sending PDU Session Establishment Complete in UL NAS transport."); + logger.info("Sending PDU Session Establishment Request in UL NAS transport."); rrc_nr->write_sdu(std::move(pdu)); return SRSRAN_SUCCESS;