diff --git a/lib/include/srslte/asn1/s1ap_utils.h b/lib/include/srslte/asn1/s1ap_utils.h index a5d6f16b3..8200d937b 100644 --- a/lib/include/srslte/asn1/s1ap_utils.h +++ b/lib/include/srslte/asn1/s1ap_utils.h @@ -26,6 +26,7 @@ struct init_context_setup_request_s; struct ue_context_mod_request_s; struct erab_setup_request_s; struct erab_release_cmd_s; +struct erab_modify_request_s; struct ue_paging_id_c; struct ho_request_s; struct sourceenb_to_targetenb_transparent_container_s; @@ -34,6 +35,7 @@ struct erab_setup_resp_s; struct rrc_establishment_cause_opts; struct cause_radio_network_opts; struct bearers_subject_to_status_transfer_item_ies_o; +struct erab_level_qos_params_s; template struct protocol_ie_single_container_s; diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 1b614713b..5f32ed787 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -425,6 +425,10 @@ public: virtual bool setup_ue_ctxt(uint16_t rnti, const asn1::s1ap::init_context_setup_request_s& msg) = 0; virtual bool modify_ue_ctxt(uint16_t rnti, const asn1::s1ap::ue_context_mod_request_s& msg) = 0; virtual bool setup_ue_erabs(uint16_t rnti, const asn1::s1ap::erab_setup_request_s& msg) = 0; + virtual void modify_erabs(uint16_t rnti, + const asn1::s1ap::erab_modify_request_s& msg, + std::vector* erabs_modified, + std::vector* erabs_failed_to_modify) = 0; virtual bool release_erabs(uint32_t rnti) = 0; virtual void release_erabs(uint32_t rnti, const asn1::s1ap::erab_release_cmd_s& msg, diff --git a/lib/include/srslte/interfaces/epc_interfaces.h b/lib/include/srslte/interfaces/epc_interfaces.h index 1a0469198..bb3de8a0e 100644 --- a/lib/include/srslte/interfaces/epc_interfaces.h +++ b/lib/include/srslte/interfaces/epc_interfaces.h @@ -63,6 +63,11 @@ public: uint32_t mme_ue_s1ap_id, std::vector erabs_to_release, struct sctp_sndrcvinfo enb_sri) = 0; + virtual bool send_erab_modify_request(uint32_t enb_ue_s1ap_id, + uint32_t mme_ue_s1ap_id, + std::map erabs_to_modify, + srslte::byte_buffer_t* nas_msg, + struct sctp_sndrcvinfo enb_sri) = 0; virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t* nas_msg, diff --git a/lib/include/srslte/rrc/rrc_cfg_utils.h b/lib/include/srslte/rrc/rrc_cfg_utils.h index 4afcc299a..f790515db 100644 --- a/lib/include/srslte/rrc/rrc_cfg_utils.h +++ b/lib/include/srslte/rrc/rrc_cfg_utils.h @@ -14,6 +14,8 @@ #define SRSLTE_RRC_CFG_UTILS_H #include "srslte/asn1/rrc_utils.h" +#include "srslte/common/common.h" +#include "srslte/common/logmap.h" #include #include @@ -289,12 +291,16 @@ void compute_cfg_diff(const toAddModList& src_list, if (&src_list == &target_list) { // early exit return; - } else if (&src_list == &add_diff_list) { + } + + if (&src_list == &add_diff_list) { // use const src_list toAddModList src_list2 = src_list; compute_cfg_diff(src_list2, target_list, add_diff_list, rem_diff_list); return; - } else if (&target_list == &add_diff_list) { + } + + if (&target_list == &add_diff_list) { // use const target_list toAddModList target_list2 = target_list; compute_cfg_diff(src_list, target_list2, add_diff_list, rem_diff_list); diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index b5343cdc4..188cb94b0 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -167,7 +167,8 @@ void rlc::reset() delete (it->second); } rlc_array.clear(); - // the multicast bearer (MRB) is not removed here because eMBMS services continue to be streamed in idle mode (3GPP TS 23.246 version 14.1.0 Release 14 section 8) + // the multicast bearer (MRB) is not removed here because eMBMS services continue to be streamed in idle mode (3GPP + // TS 23.246 version 14.1.0 Release 14 section 8) } // Add SRB0 again @@ -390,6 +391,11 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg) rlc_common* rlc_entity = nullptr; + if (cnfg.rlc_mode != rlc_mode_t::tm and rlc_array.find(lcid) != rlc_array.end()) { + // RLC entity already exists. Recreating it. + rlc_array.erase(lcid); + } + if (not valid_lcid(lcid)) { if (cnfg.rat == srslte_rat_t::lte) { switch (cnfg.rlc_mode) { diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 14d97c9e0..5c71a10bf 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -76,6 +76,14 @@ public: bool setup_ue_ctxt(uint16_t rnti, const asn1::s1ap::init_context_setup_request_s& msg) override; bool modify_ue_ctxt(uint16_t rnti, const asn1::s1ap::ue_context_mod_request_s& msg) override; bool setup_ue_erabs(uint16_t rnti, const asn1::s1ap::erab_setup_request_s& msg) override; + void modify_erabs(uint16_t rnti, + const asn1::s1ap::erab_modify_request_s& msg, + std::vector* erabs_modified, + std::vector* erabs_failed_to_modify) override; + bool modify_ue_erab(uint16_t rnti, + uint8_t erab_id, + const asn1::s1ap::erab_level_qos_params_s& qos_params, + const asn1::unbounded_octstring* nas_pdu); bool release_erabs(uint32_t rnti) override; void release_erabs(uint32_t rnti, const asn1::s1ap::erab_release_cmd_s& msg, diff --git a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h index bf4f0041e..b1e62bf49 100644 --- a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h +++ b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h @@ -69,6 +69,9 @@ public: const asn1::unbounded_octstring* nas_pdu); bool release_erab(uint8_t erab_id); void release_erabs(); + bool modify_erab(uint8_t erab_id, + const asn1::s1ap::erab_level_qos_params_s& qos, + const asn1::unbounded_octstring* nas_pdu); // Methods to apply bearer updates void add_gtpu_bearer(gtpu_interface_rrc* gtpu, uint32_t erab_id); diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index e832c8dd6..4a20183d3 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -67,6 +67,9 @@ public: bool setup_erabs(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e); bool release_erabs(); bool release_erab(uint32_t erab_id); + bool modify_erab(uint16_t erab_id, + const asn1::s1ap::erab_level_qos_params_s& qos_params, + const asn1::unbounded_octstring* nas_pdu); // handover void handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container); diff --git a/srsenb/hdr/stack/upper/s1ap.h b/srsenb/hdr/stack/upper/s1ap.h index f1e295dd4..3e27607b0 100644 --- a/srsenb/hdr/stack/upper/s1ap.h +++ b/srsenb/hdr/stack/upper/s1ap.h @@ -139,6 +139,7 @@ private: bool handle_s1setupfailure(const asn1::s1ap::s1_setup_fail_s& msg); bool handle_erabsetuprequest(const asn1::s1ap::erab_setup_request_s& msg); bool handle_erabreleasecommand(const asn1::s1ap::erab_release_cmd_s& msg); + bool handle_erabmodifyrequest(const asn1::s1ap::erab_modify_request_s& msg); bool handle_uecontextmodifyrequest(const asn1::s1ap::ue_context_mod_request_s& msg); // bool send_ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) @@ -192,6 +193,8 @@ private: bool send_erab_setup_response(const asn1::s1ap::erab_setup_resp_s& res_); bool send_erab_release_response(const std::vector& erabs_successfully_released, const std::vector& erabs_failed_to_release); + bool send_erab_modify_response(const std::vector& erabs_successfully_released, + const std::vector& erabs_failed_to_release); bool was_uectxtrelease_requested() const { return release_requested; } ue_ctxt_t ctxt = {}; diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 64e269d74..94d3514c7 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -333,6 +333,56 @@ void rrc::release_erabs(uint32_t rnti, return; } +void rrc::modify_erabs(uint16_t rnti, + const asn1::s1ap::erab_modify_request_s& msg, + std::vector* erabs_modified, + std::vector* erabs_failed_to_modify) +{ + rrc_log->info("Modifying E-RABs for 0x%x\n", rnti); + auto user_it = users.find(rnti); + + if (user_it == users.end()) { + rrc_log->warning("Unrecognised rnti: 0x%x\n", rnti); + return; + } + + // Iterate over bearers + for (uint32_t i = 0; i < msg.protocol_ies.erab_to_be_modified_list_bearer_mod_req.value.size(); i++) { + const asn1::s1ap::erab_to_be_modified_item_bearer_mod_req_s& erab_to_mod = + msg.protocol_ies.erab_to_be_modified_list_bearer_mod_req.value[i] + .value.erab_to_be_modified_item_bearer_mod_req(); + + uint32_t erab_id = erab_to_mod.erab_id; + asn1::s1ap::erab_level_qos_params_s qos_params = erab_to_mod.erab_level_qos_params; + + bool ret = modify_ue_erab(rnti, erab_id, qos_params, &erab_to_mod.nas_pdu); + if (ret) { + erabs_modified->push_back(erab_to_mod.erab_id); + } else { + erabs_failed_to_modify->push_back(erab_to_mod.erab_id); + } + } + + return; +} + +bool rrc::modify_ue_erab(uint16_t rnti, + uint8_t erab_id, + const asn1::s1ap::erab_level_qos_params_s& qos_params, + const asn1::unbounded_octstring* nas_pdu) +{ + rrc_log->info("Modifying E-RAB for 0x%x. E-RAB Id %d\n", rnti, erab_id); + auto user_it = users.find(rnti); + + if (user_it == users.end()) { + rrc_log->warning("Unrecognised rnti: 0x%x\n", rnti); + return false; + } + + bool ret = user_it->second->modify_erab(erab_id, qos_params, nas_pdu); + return ret; +} + /******************************************************************************* Paging functions These functions use a different mutex because access different shared variables diff --git a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc index ab5778ea7..c569a25c6 100644 --- a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc +++ b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc @@ -285,6 +285,23 @@ void bearer_cfg_handler::release_erabs() } } +bool bearer_cfg_handler::modify_erab(uint8_t erab_id, + const asn1::s1ap::erab_level_qos_params_s& qos, + const asn1::unbounded_octstring* nas_pdu) +{ + log_h->info("Modifying E-RAB %d\n", erab_id); + std::map::iterator erab_it = erabs.find(erab_id); + if (erab_it == erabs.end()) { + log_h->error("Could not find E-RAB to modify\n"); + return false; + } + auto address = erab_it->second.address; + uint32_t teid_out = erab_it->second.teid_out; + release_erab(erab_id); + add_erab(erab_id, qos, address, teid_out, nas_pdu); + return true; +} + void bearer_cfg_handler::add_gtpu_bearer(srsenb::gtpu_interface_rrc* gtpu, uint32_t erab_id) { auto it = erabs.find(erab_id); diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index b95f3c3c7..1df46ea74 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -838,6 +838,17 @@ bool rrc::ue::release_erab(uint32_t erab_id) return bearer_list.release_erab(erab_id); } +bool rrc::ue::modify_erab(uint16_t erab_id, + const asn1::s1ap::erab_level_qos_params_s& qos_params, + const asn1::unbounded_octstring* nas_pdu) +{ + bool ret = bearer_list.modify_erab(erab_id, qos_params, nas_pdu); + if (ret) { + send_connection_reconf(nullptr, false); + } + return ret; +} + void rrc::ue::notify_s1ap_ue_erab_setup_response(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e) { asn1::s1ap::erab_setup_resp_s res; diff --git a/srsenb/src/stack/rrc/ue_rr_cfg.cc b/srsenb/src/stack/rrc/ue_rr_cfg.cc index d561e2a47..e6f408db1 100644 --- a/srsenb/src/stack/rrc/ue_rr_cfg.cc +++ b/srsenb/src/stack/rrc/ue_rr_cfg.cc @@ -127,9 +127,7 @@ void fill_cqi_report_enb_cfg(cqi_report_cfg_s& cqi_report_cfg, const rrc_cfg_t& cqi_report_cfg.nom_pdsch_rs_epre_offset = 0; } -int fill_cqi_report_setup(cqi_report_cfg_s& cqi_rep, - const rrc_cfg_t& enb_cfg, - const ue_cell_ded_list& ue_cell_list) +int fill_cqi_report_setup(cqi_report_cfg_s& cqi_rep, const rrc_cfg_t& enb_cfg, const ue_cell_ded_list& ue_cell_list) { // eNB params set at this point @@ -148,9 +146,7 @@ int fill_cqi_report_setup(cqi_report_cfg_s& cqi_rep, return SRSLTE_SUCCESS; } -void fill_cqi_report_reconf(cqi_report_cfg_s& cqi_rep, - const rrc_cfg_t& enb_cfg, - const ue_cell_ded_list& ue_cell_list) +void fill_cqi_report_reconf(cqi_report_cfg_s& cqi_rep, const rrc_cfg_t& enb_cfg, const ue_cell_ded_list& ue_cell_list) { // Get RRC setup CQI config if (fill_cqi_report_setup(cqi_rep, enb_cfg, ue_cell_list) == SRSLTE_ERROR) { @@ -229,9 +225,7 @@ void fill_phy_cfg_ded_enb_cfg(phys_cfg_ded_s& phy_cfg, const rrc_cfg_t& enb_cfg) fill_cqi_report_enb_cfg(phy_cfg.cqi_report_cfg, enb_cfg); } -void fill_phy_cfg_ded_setup(phys_cfg_ded_s& phy_cfg, - const rrc_cfg_t& enb_cfg, - const ue_cell_ded_list& ue_cell_list) +void fill_phy_cfg_ded_setup(phys_cfg_ded_s& phy_cfg, const rrc_cfg_t& enb_cfg, const ue_cell_ded_list& ue_cell_list) { // Set PHYConfigDedicated base fill_phy_cfg_ded_enb_cfg(phy_cfg, enb_cfg); @@ -246,7 +240,7 @@ void fill_phy_cfg_ded_setup(phys_cfg_ded_s& phy_cfg, /// Fills ASN1 PhysicalConfigurationDedicated struct with eNB config params at RRCReconf void fill_phy_cfg_ded_reconf(phys_cfg_ded_s& phy_cfg, const rrc_cfg_t& enb_cfg, - const ue_cell_ded_list& ue_cell_list, + const ue_cell_ded_list& ue_cell_list, const srslte::rrc_ue_capabilities_t& ue_caps) { // Use RRCSetup as starting point @@ -296,9 +290,9 @@ void fill_rr_cfg_ded_enb_cfg(asn1::rrc::rr_cfg_ded_s& rr_cfg, const rrc_cfg_t& e rr_cfg.sps_cfg_present = false; } -void fill_rr_cfg_ded_setup(asn1::rrc::rr_cfg_ded_s& rr_cfg, - const rrc_cfg_t& enb_cfg, - const ue_cell_ded_list& ue_cell_list) +void fill_rr_cfg_ded_setup(asn1::rrc::rr_cfg_ded_s& rr_cfg, + const rrc_cfg_t& enb_cfg, + const ue_cell_ded_list& ue_cell_list) { // Establish default enb config fill_rr_cfg_ded_enb_cfg(rr_cfg, enb_cfg); @@ -315,7 +309,7 @@ void fill_rr_cfg_ded_setup(asn1::rrc::rr_cfg_ded_s& rr_cfg, void fill_rr_cfg_ded_reconf(asn1::rrc::rr_cfg_ded_s& rr_cfg, const rr_cfg_ded_s& current_rr_cfg, const rrc_cfg_t& enb_cfg, - const ue_cell_ded_list& ue_cell_list, + const ue_cell_ded_list& ue_cell_list, const bearer_cfg_handler& bearers, const srslte::rrc_ue_capabilities_t& ue_caps, bool phy_cfg_updated) @@ -389,7 +383,7 @@ void apply_rr_cfg_ded_diff(rr_cfg_ded_s& current_rr_cfg_ded, const rr_cfg_ded_s& void fill_scells_reconf(asn1::rrc::rrc_conn_recfg_r8_ies_s& recfg_r8, const scell_to_add_mod_list_r10_l& current_scells, const rrc_cfg_t& enb_cfg, - const ue_cell_ded_list& ue_cell_list, + const ue_cell_ded_list& ue_cell_list, const srslte::rrc_ue_capabilities_t& ue_caps) { // check whether there has been scell updates @@ -411,10 +405,10 @@ void fill_scells_reconf(asn1::rrc::rrc_conn_recfg_r8_ies_s& recfg_r8, scell_to_add_mod_list_r10_l target_scells(ue_cell_list.nof_cells() - 1); for (size_t ue_cc_idx = 1; ue_cc_idx < ue_cell_list.nof_cells(); ++ue_cc_idx) { - const ue_cell_ded& scell = *ue_cell_list.get_ue_cc_idx(ue_cc_idx); - const enb_cell_common& scell_cfg = *scell.cell_common; - const sib_type1_s& cell_sib1 = scell_cfg.sib1; - const sib_type2_s& cell_sib2 = scell_cfg.sib2; + const ue_cell_ded& scell = *ue_cell_list.get_ue_cc_idx(ue_cc_idx); + const enb_cell_common& scell_cfg = *scell.cell_common; + const sib_type1_s& cell_sib1 = scell_cfg.sib1; + const sib_type2_s& cell_sib2 = scell_cfg.sib2; scell_to_add_mod_r10_s& asn1cell = target_scells[ue_cc_idx - 1]; asn1cell.scell_idx_r10 = ue_cc_idx; @@ -563,7 +557,7 @@ void apply_scells_to_add_diff(asn1::rrc::scell_to_add_mod_list_r10_l& current_sc void apply_reconf_updates(asn1::rrc::rrc_conn_recfg_r8_ies_s& recfg_r8, ue_var_cfg_t& current_ue_cfg, const rrc_cfg_t& enb_cfg, - const ue_cell_ded_list& ue_cell_list, + const ue_cell_ded_list& ue_cell_list, bearer_cfg_handler& bearers, const srslte::rrc_ue_capabilities_t& ue_caps, bool phy_cfg_updated) diff --git a/srsenb/src/stack/upper/s1ap.cc b/srsenb/src/stack/upper/s1ap.cc index 1ee11e5ae..1c088898e 100644 --- a/srsenb/src/stack/upper/s1ap.cc +++ b/srsenb/src/stack/upper/s1ap.cc @@ -569,6 +569,8 @@ bool s1ap::handle_initiatingmessage(const init_msg_s& msg) return handle_erabsetuprequest(msg.value.erab_setup_request()); case s1ap_elem_procs_o::init_msg_c::types_opts::erab_release_cmd: return handle_erabreleasecommand(msg.value.erab_release_cmd()); + case s1ap_elem_procs_o::init_msg_c::types_opts::erab_modify_request: + return handle_erabmodifyrequest(msg.value.erab_modify_request()); case s1ap_elem_procs_o::init_msg_c::types_opts::ue_context_mod_request: return handle_uecontextmodifyrequest(msg.value.ue_context_mod_request()); case s1ap_elem_procs_o::init_msg_c::types_opts::ho_request: @@ -707,9 +709,12 @@ bool s1ap::handle_erabsetuprequest(const erab_setup_request_s& msg) return rrc->setup_ue_erabs(u->ctxt.rnti, msg); } -bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg) +bool s1ap::handle_erabmodifyrequest(const erab_modify_request_s& msg) { - s1ap_log->info("Received ERABReleaseCommand\n"); + s1ap_log->info("Received ERABModifyRequest\n"); + std::vector erab_successful_modified = {}; + std::vector erab_failed_to_modify = {}; + if (msg.ext) { s1ap_log->warning("Not handling S1AP message extension\n"); } @@ -718,9 +723,32 @@ bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg) return false; } + // Modify E-RABs from RRC + rrc->modify_erabs(u->ctxt.rnti, msg, &erab_successful_modified, &erab_failed_to_modify); + + // Send E-RAB modify response back to the MME + if (not u->send_erab_modify_response(erab_successful_modified, erab_failed_to_modify)) { + s1ap_log->info("Failed to send ERABReleaseResponse\n"); + return false; + } + + return true; +} + +bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg) +{ + s1ap_log->info("Received ERABReleaseCommand\n"); std::vector erab_successful_release = {}; std::vector erab_failed_to_release = {}; + if (msg.ext) { + s1ap_log->warning("Not handling S1AP message extension\n"); + } + ue* u = find_s1apmsg_user(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value); + if (u == nullptr) { + return false; + } + // Release E-RABs from RRC rrc->release_erabs(u->ctxt.rnti, msg, &erab_successful_release, &erab_failed_to_release); @@ -1279,6 +1307,47 @@ bool s1ap::ue::send_erab_release_response(const std::vector& erabs_suc return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E_RABReleaseResponse"); } + +bool s1ap::ue::send_erab_modify_response(const std::vector& erabs_successfully_modified, + const std::vector& erabs_failed_to_modify) +{ + if (not s1ap_ptr->mme_connected) { + return false; + } + + asn1::s1ap::s1ap_pdu_c tx_pdu; + tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY); + + auto& container = tx_pdu.successful_outcome().value.erab_modify_resp().protocol_ies; + container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; + container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id; + + // Fill in which E-RABs were successfully released + if (not erabs_successfully_modified.empty()) { + container.erab_modify_list_bearer_mod_res_present = true; + container.erab_modify_list_bearer_mod_res.value.resize(erabs_successfully_modified.size()); + for (uint32_t i = 0; i < container.erab_modify_list_bearer_mod_res.value.size(); i++) { + container.erab_modify_list_bearer_mod_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY_ITEM_BEARER_MOD_RES); + container.erab_modify_list_bearer_mod_res.value[i].value.erab_modify_item_bearer_mod_res().erab_id = + erabs_successfully_modified[i]; + } + } + + // Fill in which E-RABs were *not* successfully released + if (not erabs_failed_to_modify.empty()) { + container.erab_failed_to_modify_list_present = true; + container.erab_failed_to_modify_list.value.resize(erabs_failed_to_modify.size()); + for (uint32_t i = 0; i < container.erab_failed_to_modify_list.value.size(); i++) { + container.erab_failed_to_modify_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM); + container.erab_failed_to_modify_list.value[i].value.erab_item().erab_id = erabs_failed_to_modify[i]; + container.erab_failed_to_modify_list.value[i].value.erab_item().cause.set(asn1::s1ap::cause_c::types::misc); + container.erab_failed_to_modify_list.value[i].value.erab_item().cause.misc() = + asn1::s1ap::cause_misc_opts::unspecified; + } + } + + return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E_RABReleaseResponse"); +} /********************* * Handover Messages ********************/ diff --git a/srsepc/hdr/mme/s1ap.h b/srsepc/hdr/mme/s1ap.h index c458d8e1f..08363d8ef 100644 --- a/srsepc/hdr/mme/s1ap.h +++ b/srsepc/hdr/mme/s1ap.h @@ -106,6 +106,11 @@ public: uint32_t mme_ue_s1ap_id, std::vector erabs_to_release, struct sctp_sndrcvinfo enb_sri); + virtual bool send_erab_modify_request(uint32_t enb_ue_s1ap_id, + uint32_t mme_ue_s1ap_id, + std::map erabs_to_be_modified, + srslte::byte_buffer_t* nas_msg, + struct sctp_sndrcvinfo enb_sri); virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t* nas_msg, diff --git a/srsepc/hdr/mme/s1ap_erab_mngmt_proc.h b/srsepc/hdr/mme/s1ap_erab_mngmt_proc.h index 9541ca083..10ba7ef2e 100644 --- a/srsepc/hdr/mme/s1ap_erab_mngmt_proc.h +++ b/srsepc/hdr/mme/s1ap_erab_mngmt_proc.h @@ -37,6 +37,11 @@ public: uint32_t mme_ue_s1ap_id, std::vector erabs_to_release, struct sctp_sndrcvinfo enb_sri); + bool send_erab_modify_request(uint32_t enb_ue_s1ap_id, + uint32_t mme_ue_s1ap_id, + std::map erabs_to_modify, + srslte::byte_buffer_t* nas_msg, + struct sctp_sndrcvinfo enb_sri); bool handle_erab_release_response(const asn1::s1ap::init_context_setup_resp_s& in_ctxt_resp); private: diff --git a/srsepc/src/mme/s1ap.cc b/srsepc/src/mme/s1ap.cc index d4ff52323..42d807033 100644 --- a/srsepc/src/mme/s1ap.cc +++ b/srsepc/src/mme/s1ap.cc @@ -630,6 +630,16 @@ bool s1ap::send_erab_release_command(uint32_t enb_ue_s1ap_id, enb_ue_s1ap_id, mme_ue_s1ap_id, erabs_to_be_released, enb_sri); } +bool s1ap::send_erab_modify_request(uint32_t enb_ue_s1ap_id, + uint32_t mme_ue_s1ap_id, + std::map erabs_to_be_modified, + srslte::byte_buffer_t* nas_msg, + struct sctp_sndrcvinfo enb_sri) +{ + return m_s1ap_erab_mngmt_proc->send_erab_modify_request( + enb_ue_s1ap_id, mme_ue_s1ap_id, erabs_to_be_modified, nas_msg, enb_sri); +} + bool s1ap::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t* nas_msg, diff --git a/srsepc/src/mme/s1ap_erab_mngmt_proc.cc b/srsepc/src/mme/s1ap_erab_mngmt_proc.cc index c32aa8836..01d282d43 100644 --- a/srsepc/src/mme/s1ap_erab_mngmt_proc.cc +++ b/srsepc/src/mme/s1ap_erab_mngmt_proc.cc @@ -96,4 +96,51 @@ bool s1ap_erab_mngmt_proc::send_erab_release_command(uint32_t enb_ return true; } +bool s1ap_erab_mngmt_proc::send_erab_modify_request(uint32_t enb_ue_s1ap_id, + uint32_t mme_ue_s1ap_id, + std::map erabs_to_modify, + srslte::byte_buffer_t* nas_msg, + struct sctp_sndrcvinfo enb_sri) +{ + m_s1ap_log->info("Preparing to send E-RAB Modify Command\n"); + + // Prepare reply PDU + s1ap_pdu_t tx_pdu; + tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY); + + asn1::s1ap::erab_modify_request_ies_container& erab_mod_req = + tx_pdu.init_msg().value.erab_modify_request().protocol_ies; + + // Add MME and eNB S1AP Ids + erab_mod_req.enb_ue_s1ap_id.value = enb_ue_s1ap_id; + erab_mod_req.mme_ue_s1ap_id.value = mme_ue_s1ap_id; + + // Number of E-RABs to be setup + erab_mod_req.erab_to_be_modified_list_bearer_mod_req.value.resize(erabs_to_modify.size()); + uint32_t i = 0; + for (auto erab_it = erabs_to_modify.begin(); erab_it != erabs_to_modify.end(); erab_it++) { + erab_mod_req.erab_to_be_modified_list_bearer_mod_req.value[i].load_info_obj( + ASN1_S1AP_ID_ERAB_TO_BE_MODIFIED_ITEM_BEARER_MOD_REQ); + asn1::s1ap::erab_to_be_modified_item_bearer_mod_req_s& erab_to_mod = + erab_mod_req.erab_to_be_modified_list_bearer_mod_req.value[i].value.erab_to_be_modified_item_bearer_mod_req(); + erab_to_mod.erab_id = erab_it->first; + erab_to_mod.erab_level_qos_params.qci = erab_it->second; + erab_to_mod.erab_level_qos_params.alloc_retention_prio.prio_level = 15; // lowest + erab_to_mod.erab_level_qos_params.alloc_retention_prio.pre_emption_cap = + asn1::s1ap::pre_emption_cap_opts::shall_not_trigger_pre_emption; + erab_to_mod.erab_level_qos_params.alloc_retention_prio.pre_emption_vulnerability = + asn1::s1ap::pre_emption_vulnerability_opts::not_pre_emptable; + erab_to_mod.nas_pdu.resize(nas_msg->N_bytes); + memcpy(erab_to_mod.nas_pdu.data(), nas_msg->msg, nas_msg->N_bytes); + m_s1ap_log->info("Sending release comman to E-RAB Id %d\n", erab_it->first); + i++; + } + + if (!m_s1ap->s1ap_tx_pdu(tx_pdu, &enb_sri)) { + m_s1ap_log->error("Error sending Initial Context Setup Request.\n"); + return false; + } + return true; +} + } // namespace srsepc