diff --git a/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h b/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h index fba566f6c..883749d37 100644 --- a/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h @@ -29,6 +29,7 @@ public: 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 int release_bearers(uint16_t rnti) = 0; virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0; }; diff --git a/srsenb/hdr/stack/ngap/ngap_interfaces.h b/srsenb/hdr/stack/ngap/ngap_interfaces.h index 44cd77425..12dbf1975 100644 --- a/srsenb/hdr/stack/ngap/ngap_interfaces.h +++ b/srsenb/hdr/stack/ngap/ngap_interfaces.h @@ -21,9 +21,10 @@ 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; + 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; + virtual bool send_ue_ctxt_release_complete() = 0; }; } // namespace srsenb diff --git a/srsenb/hdr/stack/ngap/ngap_ue.h b/srsenb/hdr/stack/ngap/ngap_ue.h index 77004fdc0..4515b1fef 100644 --- a/srsenb/hdr/stack/ngap/ngap_ue.h +++ b/srsenb/hdr/stack/ngap/ngap_ue.h @@ -44,6 +44,8 @@ public: bool send_pdu_session_resource_setup_response(uint16_t pdu_session_id, uint32_t teid_in, asn1::bounded_bitstring<1, 160, true, true> addr_in); + // TS 38.413 - Section 9.2.1.2 - UE Context Release Complete + bool send_ue_ctxt_release_complete(); // 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 diff --git a/srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h b/srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h index ed4c3bdeb..d54db909d 100644 --- a/srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h +++ b/srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h @@ -54,6 +54,8 @@ public: uint32_t& teid_in, asn1::ngap_nr::cause_c& cause); + int reset_pdu_sessions(uint16_t rnti); + private: gtpu_interface_rrc* gtpu = nullptr; rrc_interface_ngap_nr* rrc = nullptr; diff --git a/srsenb/hdr/stack/ngap/ngap_ue_proc.h b/srsenb/hdr/stack/ngap/ngap_ue_proc.h index 71ddd58a0..3d1cad5e1 100644 --- a/srsenb/hdr/stack/ngap/ngap_ue_proc.h +++ b/srsenb/hdr/stack/ngap/ngap_ue_proc.h @@ -16,12 +16,12 @@ #include "ngap_interfaces.h" #include "ngap_ue_utils.h" +#include "srsenb/hdr/stack/ngap/ngap_ue_bearer_manager.h" #include "srsran/asn1/asn1_utils.h" #include "srsran/asn1/ngap.h" #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 @@ -57,6 +57,7 @@ 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_bearer_manager* bearer_manager, srslog::basic_logger& logger_); srsran::proc_outcome_t init(const asn1::ngap_nr::ue_context_release_cmd_s& msg); srsran::proc_outcome_t step(); @@ -64,8 +65,9 @@ public: private: ngap_ue_ctxt_t* ue_ctxt; - ngap_interface_ngap_proc* parent = nullptr; - rrc_interface_ngap_nr* rrc = nullptr; + ngap_interface_ngap_proc* parent = nullptr; + rrc_interface_ngap_nr* rrc = nullptr; + ngap_ue_bearer_manager* bearer_manager = nullptr; srslog::basic_logger& logger; }; diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index a680068be..4fa9b3bfb 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -95,6 +95,7 @@ public: 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); + int release_bearers(uint16_t rnti); 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); diff --git a/srsenb/src/stack/ngap/ngap.cc b/srsenb/src/stack/ngap/ngap.cc index e3660d749..3b3d604bb 100644 --- a/srsenb/src/stack/ngap/ngap.cc +++ b/srsenb/src/stack/ngap/ngap.cc @@ -112,7 +112,7 @@ ngap::ngap(srsran::task_sched_handle task_sched_, ngap::~ngap() {} -int ngap::init(const ngap_args_t& args_, rrc_interface_ngap_nr* rrc_, gtpu_interface_rrc * gtpu_) +int ngap::init(const ngap_args_t& args_, rrc_interface_ngap_nr* rrc_, gtpu_interface_rrc* gtpu_) { rrc = rrc_; args = args_; @@ -537,14 +537,21 @@ bool ngap::handle_initial_ctxt_setup_request(const asn1::ngap_nr::init_context_s bool ngap::handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg) { - // TODO: UE Context Release Command contains a list of ue_ngap_ids + const asn1::ngap_nr::ue_ngap_id_pair_s& ue_ngap_id_pair = msg.protocol_ies.ue_ngap_ids.value.ue_ngap_id_pair(); + + ue* u = handle_ngapmsg_ue_id(ue_ngap_id_pair.ran_ue_ngap_id, ue_ngap_id_pair.amf_ue_ngap_id); + if (u == nullptr) { + logger.warning("Can not find UE"); + return false; + } + + u->handle_ue_ctxt_release_cmd(msg); return true; } 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) { diff --git a/srsenb/src/stack/ngap/ngap_ue.cc b/srsenb/src/stack/ngap/ngap_ue.cc index 5fc7f5e86..b3fa39137 100644 --- a/srsenb/src/stack/ngap/ngap_ue.cc +++ b/srsenb/src/stack/ngap/ngap_ue.cc @@ -31,7 +31,7 @@ ngap::ue::ue(ngap* ngap_ptr_, ngap_ptr(ngap_ptr_), 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_context_release_proc(this, rrc_ptr_, &ctxt, &bearer_manager, 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++; @@ -223,6 +223,30 @@ bool ngap::ue::send_pdu_session_resource_setup_response(uint16_t return ngap_ptr->sctp_send_ngap_pdu(tx_pdu, ctxt.rnti, "PDUSessionResourceSetupResponse"); } +bool ngap::ue::send_ue_ctxt_release_complete() +{ + if (not ngap_ptr->amf_connected) { + logger.warning("AMF not connected"); + return false; + } + + ngap_pdu_c tx_pdu; + tx_pdu.set_successful_outcome().load_info_obj(ASN1_NGAP_NR_ID_UE_CONTEXT_RELEASE); + ue_context_release_complete_s& container = tx_pdu.successful_outcome().value.ue_context_release_complete(); + + // userLocationInformationNR + container.protocol_ies.user_location_info.value.set_user_location_info_nr(); + container.protocol_ies.user_location_info.value.user_location_info_nr().nr_cgi.nrcell_id = ngap_ptr->nr_cgi.nrcell_id; + container.protocol_ies.user_location_info.value.user_location_info_nr().nr_cgi.plmn_id = ngap_ptr->nr_cgi.plmn_id; + container.protocol_ies.user_location_info.value.user_location_info_nr().tai.plmn_id = ngap_ptr->tai.plmn_id; + container.protocol_ies.user_location_info.value.user_location_info_nr().tai.tac = ngap_ptr->tai.tac; + + container.protocol_ies.ran_ue_ngap_id.value = ctxt.ran_ue_ngap_id; + container.protocol_ies.amf_ue_ngap_id.value = ctxt.amf_ue_ngap_id.value(); + + return ngap_ptr->sctp_send_ngap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseComplete"); +} + /******************************************************************************* /* 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 index 19c71526f..57e776f8d 100644 --- a/srsenb/src/stack/ngap/ngap_ue_bearer_manager.cc +++ b/srsenb/src/stack/ngap/ngap_ue_bearer_manager.cc @@ -61,6 +61,15 @@ int ngap_ue_bearer_manager::add_pdu_session(uint16_t return SRSRAN_SUCCESS; } +int ngap_ue_bearer_manager::reset_pdu_sessions(uint16_t rnti) +{ + for (auto iter = pdu_session_list.begin(); iter != pdu_session_list.end(); iter++) { + auto pdu_session_id = iter->first; + rem_gtpu_bearer(pdu_session_id, rnti); + } + return true; +} + int ngap_ue_bearer_manager::add_gtpu_bearer(uint16_t rnti, uint32_t lcid, uint32_t pdu_session_id, diff --git a/srsenb/src/stack/ngap/ngap_ue_proc.cc b/srsenb/src/stack/ngap/ngap_ue_proc.cc index ad61f8c6c..698beba11 100644 --- a/srsenb/src/stack/ngap/ngap_ue_proc.cc +++ b/srsenb/src/stack/ngap/ngap_ue_proc.cc @@ -66,19 +66,23 @@ 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_, + ngap_ue_bearer_manager* bearer_manager_, srslog::basic_logger& logger_) : logger(logger_) { - parent = parent_; - rrc = rrc_; - ue_ctxt = ue_ctxt_; + parent = parent_; + rrc = rrc_; + ue_ctxt = ue_ctxt_; + bearer_manager = bearer_manager_; }; proc_outcome_t ngap_ue_ue_context_release_proc::init(const asn1::ngap_nr::ue_context_release_cmd_s& msg) { - // 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()); + // TODO: How to approach erasing users ? + bearer_manager->reset_pdu_sessions(ue_ctxt->rnti); + rrc->release_bearers(ue_ctxt->rnti); + parent->send_initial_ctxt_setup_response(); return proc_outcome_t::success; } diff --git a/srsenb/src/stack/rrc/rrc_nr.cc b/srsenb/src/stack/rrc/rrc_nr.cc index fc8fc7c7b..9968128d8 100644 --- a/srsenb/src/stack/rrc/rrc_nr.cc +++ b/srsenb/src/stack/rrc/rrc_nr.cc @@ -450,6 +450,11 @@ int rrc_nr::establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran: return SRSRAN_SUCCESS; } +int rrc_nr::release_bearers(uint16_t rnti) +{ + return SRSRAN_SUCCESS; +} + int rrc_nr::allocate_lcid(uint16_t rnti) { return SRSRAN_SUCCESS; diff --git a/srsenb/test/ngap/ngap_test.cc b/srsenb/test/ngap/ngap_test.cc index 117ace1bb..8b6f8baf1 100644 --- a/srsenb/test/ngap/ngap_test.cc +++ b/srsenb/test/ngap/ngap_test.cc @@ -86,6 +86,7 @@ public: { return SRSRAN_SUCCESS; } + int release_bearers(uint16_t rnti) { 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) {} }; diff --git a/srsue/hdr/stack/upper/nas_5g.h b/srsue/hdr/stack/upper/nas_5g.h index 27ebc2141..85083b890 100644 --- a/srsue/hdr/stack/upper/nas_5g.h +++ b/srsue/hdr/stack/upper/nas_5g.h @@ -80,7 +80,7 @@ private: srsran::nas_5g::nas_5gs_msg initial_registration_request_stored; - nas_args_t cfg = {}; + nas_args_t cfg = {}; mm5g_state_t state; // Security @@ -132,10 +132,12 @@ private: int send_pdu_session_establishment_request(uint32_t transaction_identity, uint16_t pdu_session_id, const pdu_session_cfg_t& pdu_session); + int send_deregistration_request_ue_originating(); void fill_security_caps(srsran::nas_5g::ue_security_capability_t& sec_caps); int apply_security_config(srsran::unique_byte_buffer_t& pdu, uint8_t sec_hdr_type); - + int handle_deregistration_accept_ue_originating( + srsran::nas_5g::deregistration_accept_ue_originating_t& deregistration_accept_ue_originating); // message handler int handle_registration_accept(srsran::nas_5g::registration_accept_t& registration_accept); int handle_registration_reject(srsran::nas_5g::registration_reject_t& registration_reject); @@ -168,6 +170,7 @@ private: int configure_pdu_session(uint16_t pdu_session_id); bool unestablished_pdu_sessions(); int get_unestablished_pdu_session(uint16_t& pdu_session_id, pdu_session_cfg_t& pdu_session_cfg); + int reset_pdu_sessions(); struct pdu_session_t { bool configured; diff --git a/srsue/src/stack/upper/nas_5g.cc b/srsue/src/stack/upper/nas_5g.cc index 660b87600..b28c58b4d 100644 --- a/srsue/src/stack/upper/nas_5g.cc +++ b/srsue/src/stack/upper/nas_5g.cc @@ -136,6 +136,7 @@ void nas_5g::run_tti() break; case mm5g_state_t::state_t::deregistered_initiated: logger.debug("UE detaching..."); + send_deregistration_request_ue_originating(); break; default: break; @@ -222,6 +223,9 @@ int nas_5g::write_pdu(srsran::unique_byte_buffer_t pdu) case msg_opts::options::dl_nas_transport: handle_dl_nas_transport(nas_msg.dl_nas_transport()); break; + case msg_opts::options::deregistration_accept_ue_originating: + handle_deregistration_accept_ue_originating(nas_msg.deregistration_accept_ue_originating()); + break; default: logger.error( "Not handling NAS message type: %s (0x%02x)", nas_msg.hdr.message_type.to_string(), nas_msg.hdr.message_type); @@ -587,6 +591,51 @@ int nas_5g::send_pdu_session_establishment_request(uint32_t tran return SRSRAN_SUCCESS; } +int nas_5g::send_deregistration_request_ue_originating() +{ + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + if (!pdu) { + logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); + return SRSRAN_ERROR; + } + + logger.info("Generating Deregistration Request (UE Originating)"); + + nas_5gs_msg nas_msg; + deregistration_request_ue_originating_t& deregistration_request = nas_msg.set_deregistration_request_ue_originating(); + + // Note 5.5.2.2.2 : AMF does not send a Deregistration Accept NAS message if De-registration type IE indicates "switch + // off" + deregistration_request.de_registration_type.switch_off.value = + de_registration_type_t::switch_off_type_::options::normal_de_registration; + + mobile_identity_5gs_t::suci_s& suci = deregistration_request.mobile_identity_5gs.set_suci(); + suci.supi_format = mobile_identity_5gs_t::suci_s::supi_format_type_::options::imsi; + usim->get_home_mcc_bytes(suci.mcc.data(), suci.mcc.size()); + usim->get_home_mnc_bytes(suci.mnc.data(), suci.mnc.size()); + + deregistration_request.ng_ksi.nas_key_set_identifier.value = + key_set_identifier_t::nas_key_set_identifier_type_::options::no_key_is_available_or_reserved; + + if (nas_msg.pack(pdu) != SRSASN_SUCCESS) { + logger.error("Failed to pack Deregistration Request (UE Originating)."); + return SRSRAN_ERROR; + } + + if (pcap != nullptr) { + pcap->write_nas(pdu.get()->msg, pdu.get()->N_bytes); + } + + logger.info("Sending Deregistration Request (UE Originating)"); + rrc_nr->write_sdu(std::move(pdu)); + + reset_pdu_sessions(); + + // TODO: Delete / Reset context (ctxt & ctxt_5g) + + return SRSASN_SUCCESS; +} + // Message handler int nas_5g::handle_registration_accept(registration_accept_t& registration_accept) { @@ -797,6 +846,13 @@ int nas_5g::handle_n1_sm_information(std::vector payload_container_cont return SRSRAN_SUCCESS; } +int nas_5g::handle_deregistration_accept_ue_originating( + srsran::nas_5g::deregistration_accept_ue_originating_t& deregistration_accept_ue_originating) +{ + logger.info("Received Deregistration Request (UE Originating)"); + return SRSASN_SUCCESS; +} + /******************************************************************************* * NAS Timers ******************************************************************************/ @@ -823,7 +879,7 @@ int nas_5g::switch_on() int nas_5g::switch_off() { logger.info("Switching off"); - // TODO + state.set_deregistered_initiated(); return SRSRAN_SUCCESS; } @@ -847,6 +903,16 @@ int nas_5g::start_service_request() return SRSRAN_SUCCESS; } +int nas_5g::reset_pdu_sessions() +{ + for (auto pdu_session : pdu_sessions) { + pdu_session.established = false; + pdu_session.pdu_session_id = 0; + } + + return SRSRAN_SUCCESS; +} + /******************************************************************************* * Helpers ******************************************************************************/ @@ -905,7 +971,7 @@ void nas_5g::fill_security_caps(srsran::nas_5g::ue_security_capability_t& sec_ca } /******************************************************************************* - * Helpers for Session Management + * Helpers for Session Management ******************************************************************************/ int nas_5g::trigger_pdu_session_est()