diff --git a/srsgnb/hdr/stack/rrc/rrc_nr.h b/srsgnb/hdr/stack/rrc/rrc_nr.h index eac2f93f8..6891aa661 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr.h @@ -103,6 +103,7 @@ public: void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) final; int set_aggregate_max_bitrate(uint16_t rnti, const asn1::ngap_nr::ue_aggregate_maximum_bit_rate_s& rates) final; int allocate_lcid(uint16_t rnti) final; + int start_rrc_reconfiguration(uint16_t rnti); // logging typedef enum { Rx = 0, Tx } direction_t; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_ue.h b/srsgnb/hdr/stack/rrc/rrc_nr_ue.h index 7135dd0d5..910bf5986 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_ue.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_ue.h @@ -83,6 +83,9 @@ public: /* TS 38.331 - 5.3.4 Initial AS security activation */ void send_security_mode_command(srsran::unique_byte_buffer_t nas_pdu); + /* TS 38.331 - 5.3.5 RRC reconfiguration */ + void send_rrc_reconfiguration(); + private: int send_dl_ccch(const asn1::rrc_nr::dl_ccch_msg_s& dl_ccch_msg); int send_dl_dcch(srsran::nr_srb srb, const asn1::rrc_nr::dl_dcch_msg_s& dl_dcch_msg); @@ -91,9 +94,6 @@ private: void send_rrc_setup(); void send_rrc_reject(uint8_t reject_wait_time_secs); - /* TS 38.331 - 5.3.5 RRC reconfiguration */ - void send_rrc_reconfiguration(); - /// Update PDCP bearers based on ASN1 structs passed to the UE int update_pdcp_bearers(const asn1::rrc_nr::radio_bearer_cfg_s& radio_bearer_diff, const asn1::rrc_nr::cell_group_cfg_s& cell_group_diff); diff --git a/srsgnb/src/stack/ngap/ngap_ue_proc.cc b/srsgnb/src/stack/ngap/ngap_ue_proc.cc index 31f7b6247..4ff9615f4 100644 --- a/srsgnb/src/stack/ngap/ngap_ue_proc.cc +++ b/srsgnb/src/stack/ngap/ngap_ue_proc.cc @@ -169,7 +169,7 @@ proc_outcome_t ngap_ue_pdu_session_res_setup_proc::init(const asn1::ngap_nr::pdu // QoS parameter mapping in config in LTE enb if (su_req.pdu_session_nas_pdu_present) { - if (rrc->establish_rrc_bearer(ue_ctxt->rnti, su_req.pdu_session_id, su_req.pdu_session_nas_pdu, lcid) == + 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_in, addr_in); return proc_outcome_t::success; diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index e3262d764..8f705acd2 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -15,6 +15,7 @@ #include "srsran/asn1/rrc_nr_utils.h" #include "srsran/common/band_helper.h" #include +#include using namespace asn1::rrc_nr; @@ -1153,7 +1154,8 @@ void fill_cellgroup_with_radio_bearer_cfg(const rrc_nr_cfg_t& // Add DRBs for (const drb_to_add_mod_s& drb : bearers.drb_to_add_mod_list) { out.rlc_bearer_to_add_mod_list.push_back({}); - fill_srb(cfg, (srsran::nr_srb)drb.drb_id, out.rlc_bearer_to_add_mod_list.back()); + uint32_t lcid = drb_to_lcid(static_cast(drb.drb_id)); + fill_drb(cfg, lcid, (srsran::nr_drb)drb.drb_id, out.rlc_bearer_to_add_mod_list.back()); } out.rlc_bearer_to_add_mod_list_present = out.rlc_bearer_to_add_mod_list.size() > 0; diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 3790a3b53..f1b0b2614 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -634,7 +634,16 @@ void rrc_nr::write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) } users[rnti]->send_dl_information_transfer(std::move(sdu)); } - +int rrc_nr::start_rrc_reconfiguration(uint16_t rnti) +{ + auto user_it = users.find(rnti); + if (user_it == users.end()){ + logger.error("Starting RRCRecofiguration failed - rnti=0x%x not found", rnti); + return SRSRAN_ERROR; + } + user_it->second->send_rrc_reconfiguration(); + return SRSRAN_SUCCESS; +} /******************************************************************************* Interface for EUTRA RRC *******************************************************************************/ diff --git a/srsgnb/src/stack/rrc/rrc_nr_ue.cc b/srsgnb/src/stack/rrc/rrc_nr_ue.cc index 969715912..9f06e2e54 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_ue.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_ue.cc @@ -1056,6 +1056,11 @@ void rrc_nr::ue::send_rrc_reconfiguration() } ies.non_crit_ext.master_cell_group.resize(pdu->N_bytes); memcpy(ies.non_crit_ext.master_cell_group.data(), pdu->data(), pdu->N_bytes); + if (logger.debug.enabled()) { + asn1::json_writer js; + master_cell_group.to_json(js); + logger.debug("Containerized MasterCellGroup: %s", js.to_string().c_str()); + } // Pass stored NAS PDUs ies.non_crit_ext.ded_nas_msg_list_present = true; @@ -1086,6 +1091,8 @@ void rrc_nr::ue::send_rrc_reconfiguration() void rrc_nr::ue::handle_rrc_reconfiguration_complete(const asn1::rrc_nr::rrc_recfg_complete_s& msg) { + update_mac(next_cell_group_cfg, true); + radio_bearer_cfg = next_radio_bearer_cfg; cell_group_cfg = next_cell_group_cfg; parent->ngap->ue_notify_rrc_reconf_complete(rnti, true); diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc index a80dc039b..24998dc21 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc @@ -161,6 +161,7 @@ void test_rrc_sa_connection() test_rrc_nr_connection_establishment(task_sched, rrc_obj, rlc_obj, mac_obj, ngap_obj,0x4601); test_rrc_nr_info_transfer(task_sched, rrc_obj, pdcp_obj, ngap_obj, 0x4601); test_rrc_nr_security_mode_cmd(task_sched, rrc_obj, pdcp_obj, 0x4601); + test_rrc_nr_reconfiguration( task_sched, rrc_obj, pdcp_obj, 0x4601); } } // namespace srsenb diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc b/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc index e6db8e7b4..459f39703 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc @@ -123,7 +123,7 @@ void test_rrc_nr_connection_establishment(srsran::task_scheduler& task_sched, TESTASSERT(ss_ue_found); /// Ensure UE-specific SearchSpace was added // Check here if the MSG sent to NGAP is correct - // Create a srsran::span object for the expected MSG + // Create a unbounded_octstring for the expected MSG asn1::unbounded_octstring expected; expected.from_string(NAS_msg_str); TESTASSERT(expected == ngap.last_pdu); @@ -151,7 +151,7 @@ void test_rrc_nr_info_transfer(srsran::task_scheduler& task_sched, // Test whether there exists the SRB1 initiated in the Connection Establishment // We test this as the SRB1 was setup in a different function TESTASSERT_EQ(rnti, pdcp.last_sdu_rnti); - TESTASSERT_EQ(srsran::srb_to_lcid(srsran::nr_srb::srb1), 1); + TESTASSERT_EQ(srsran::srb_to_lcid(srsran::nr_srb::srb1), pdcp.last_sdu_lcid); // Send SecurityModeCommand (gNB -> UE) dl_dcch_msg_s dl_dcch_msg; @@ -175,7 +175,8 @@ void test_rrc_nr_info_transfer(srsran::task_scheduler& task_sched, auto& ies_UL = ul_dcch_msg.msg.set_c1().set_ul_info_transfer().crit_exts.set_ul_info_transfer(); ies_UL.ded_nas_msg_present = true; - // create an unbounded_octstring object that contains a random NAS message (we simulate a NAS message) + // Create an unbounded_octstring object that contains a random NAS message (we simulate a NAS message) + // We reuse NAS_UL_msg below to compare the string with the message sent to and unpacked by the gNB asn1::unbounded_octstring NAS_UL_msg; NAS_UL_msg.from_string("6671f8bc80b1860f29b3a8b3b8563ce6c36a591bb1a3dc6612674448fb958d274426d326356aa9aa"); ies_UL.ded_nas_msg.resize(NAS_UL_msg.size()); @@ -192,7 +193,7 @@ void test_rrc_nr_info_transfer(srsran::task_scheduler& task_sched, // send message to RRC rrc_obj.write_pdu(rnti, 1, std::move(pdu)); - // get a span for both NAS msg and compare if the actual transmitted is correct + // compare if the actual transmitted matches with the MSG created from the original string TESTASSERT(NAS_UL_msg == ngap.last_pdu); } @@ -209,9 +210,9 @@ void test_rrc_nr_security_mode_cmd(srsran::task_scheduler& task_sched, // Test whether there exists the SRB1 initiated in the Connection Establishment // We test this as the SRB1 was setup in a different function TESTASSERT_EQ(rnti, pdcp.last_sdu_rnti); - TESTASSERT_EQ(srsran::srb_to_lcid(srsran::nr_srb::srb1), 1); + TESTASSERT_EQ(srsran::srb_to_lcid(srsran::nr_srb::srb1), pdcp.last_sdu_lcid); - // Send SecurityModeCommand (gNB -> UE) + // STEP 1 - Send SecurityModeCommand (gNB -> UE) dl_dcch_msg_s dl_dcch_msg; { asn1::cbit_ref bref{pdcp.last_sdu->data(), pdcp.last_sdu->size()}; @@ -228,7 +229,7 @@ void test_rrc_nr_security_mode_cmd(srsran::task_scheduler& task_sched, ies.security_cfg_smc.security_algorithm_cfg.integrity_prot_algorithm.value); TESTASSERT_EQ(ciphering_algorithm_opts::nea0, ies.security_cfg_smc.security_algorithm_cfg.ciphering_algorithm.value); - // Send SecurityModeComplete (UE -> gNB) + // STEP 2 - Send SecurityModeComplete (UE -> gNB) ul_dcch_msg_s ul_dcch_msg; auto& sec_cmd_complete_msg = ul_dcch_msg.msg.set_c1().set_security_mode_complete(); sec_cmd_complete_msg.rrc_transaction_id = dl_dcch_msg.msg.c1().security_mode_cmd().rrc_transaction_id; @@ -245,4 +246,85 @@ void test_rrc_nr_security_mode_cmd(srsran::task_scheduler& task_sched, rrc_obj.write_pdu(rnti, 1, std::move(pdu)); } +void test_rrc_nr_reconfiguration(srsran::task_scheduler& task_sched, + rrc_nr& rrc_obj, + pdcp_nr_rrc_tester& pdcp, + uint16_t rnti) +{ + TESTASSERT_EQ(srsran::srb_to_lcid(srsran::nr_srb::srb1), pdcp.last_sdu_lcid); + + // create an unbounded_octstring object that contains a random NAS message (we simulate a NAS message) + asn1::unbounded_octstring NAS_msg; + NAS_msg.from_string("c574defc80ba722bffb8eacb6f8a163e3222cf1542ac529f6980bb15e0bf12d9f2b29f11fb458ec9"); + rrc_obj.establish_rrc_bearer(rnti, 1, NAS_msg, srsran::srb_to_lcid(srsran::nr_srb::srb1)); + + // STEP 2 - Trigger and send RRCReconfiguration command (gNB -> UE) + rrc_obj.start_rrc_reconfiguration(rnti); + + // Test whether there exists the SRB1 initiated in the Connection Establishment + // We test this as the SRB1 was set up in a different function + TESTASSERT_EQ(rnti, pdcp.last_sdu_rnti); + TESTASSERT_EQ(srsran::srb_to_lcid(srsran::nr_srb::srb1), pdcp.last_sdu_lcid); + + dl_dcch_msg_s dl_dcch_msg; + { + asn1::cbit_ref bref{pdcp.last_sdu->data(), pdcp.last_sdu->size()}; + TESTASSERT_SUCCESS(dl_dcch_msg.unpack(bref)); + } + + // Test whether the unpacked message is correct + TESTASSERT_EQ(dl_dcch_msg_type_c::types_opts::c1, dl_dcch_msg.msg.type().value); + TESTASSERT_EQ(dl_dcch_msg_type_c::c1_c_::types_opts::rrc_recfg, dl_dcch_msg.msg.c1().type().value); + TESTASSERT_EQ(rrc_recfg_s::crit_exts_c_::types_opts::rrc_recfg, + dl_dcch_msg.msg.c1().rrc_recfg().crit_exts.type().value); + const rrc_recfg_ies_s& reconf_ies = dl_dcch_msg.msg.c1().rrc_recfg().crit_exts.rrc_recfg(); + TESTASSERT_EQ(true, reconf_ies.radio_bearer_cfg_present); + TESTASSERT_EQ(true, reconf_ies.radio_bearer_cfg.srb_to_add_mod_list_present); + TESTASSERT_EQ(1, reconf_ies.radio_bearer_cfg.srb_to_add_mod_list.size()); + TESTASSERT_EQ(2, reconf_ies.radio_bearer_cfg.srb_to_add_mod_list[0].srb_id); + TESTASSERT_EQ(1, reconf_ies.radio_bearer_cfg.drb_to_add_mod_list.size()); + auto& drb = reconf_ies.radio_bearer_cfg.drb_to_add_mod_list[0]; + TESTASSERT_EQ(1, drb.drb_id); + + TESTASSERT_EQ(true, reconf_ies.non_crit_ext_present); + TESTASSERT_EQ(true, reconf_ies.non_crit_ext.master_cell_group_present); + auto& master_group_msg = reconf_ies.non_crit_ext.master_cell_group; + + cell_group_cfg_s master_cell_group; + { + asn1::cbit_ref bref{master_group_msg.data(), master_group_msg.size()}; + TESTASSERT_SUCCESS(master_cell_group.unpack(bref)); + } + + // Test if the master_cell_group SRB and DRB IDs match those in the RadioBearerConfig + TESTASSERT_EQ(0, master_cell_group.cell_group_id); + TESTASSERT_EQ(true, master_cell_group.rlc_bearer_to_add_mod_list_present); + auto& rlc_srb = master_cell_group.rlc_bearer_to_add_mod_list[0]; + TESTASSERT_EQ(reconf_ies.radio_bearer_cfg.srb_to_add_mod_list[0].srb_id, rlc_srb.served_radio_bearer.srb_id()); + auto& rlc_drb = master_cell_group.rlc_bearer_to_add_mod_list[1]; + TESTASSERT_EQ(reconf_ies.radio_bearer_cfg.drb_to_add_mod_list[1].drb_id, rlc_drb.served_radio_bearer.drb_id()); + + asn1::unbounded_octstring expected_nas; + expected_nas.from_string("c574defc80ba722bffb8eacb6f8a163e3222cf1542ac529f6980bb15e0bf12d9f2b29f11fb458ec9"); + TESTASSERT_EQ(true, reconf_ies.non_crit_ext.ded_nas_msg_list_present); + TESTASSERT( expected_nas == reconf_ies.non_crit_ext.ded_nas_msg_list[0]); + + // STEP 2 - Send RRCReconfiguration (UE -> gNB) + ul_dcch_msg_s ul_dcch_msg; + auto& RRC_recfg_complete = ul_dcch_msg.msg.set_c1().set_rrc_recfg_complete(); + RRC_recfg_complete.rrc_transaction_id = dl_dcch_msg.msg.c1().rrc_recfg().rrc_transaction_id; + RRC_recfg_complete.crit_exts.set_rrc_recfg_complete(); + + srsran::unique_byte_buffer_t pdu; + { + pdu = srsran::make_byte_buffer(); + asn1::bit_ref bref{pdu->data(), pdu->get_tailroom()}; + TESTASSERT_SUCCESS(ul_dcch_msg.pack(bref)); + pdu->N_bytes = bref.distance_bytes(); + } + + // send message to RRC + rrc_obj.write_pdu(rnti, 1, std::move(pdu)); +} + } // namespace srsenb diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.h b/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.h index 6ed82ea88..166cb1c65 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.h +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.h @@ -103,6 +103,11 @@ void test_rrc_nr_security_mode_cmd(srsran::task_scheduler& task_sched, pdcp_nr_rrc_tester& pdcp, uint16_t rnti); +void test_rrc_nr_reconfiguration(srsran::task_scheduler& task_sched, + rrc_nr& rrc_obj, + pdcp_nr_rrc_tester& pdcp, + uint16_t rnti); + } // namespace srsenb #endif // SRSRAN_RRC_NR_TEST_HELPERS_H