From 1407983c7599c641805a425c35acfba5997818cd Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 8 Dec 2021 10:03:53 +0100 Subject: [PATCH] Add decoding of RRC setup. --- srsue/hdr/stack/rrc_nr/rrc_nr.h | 11 +- srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h | 20 +++ srsue/src/stack/rrc_nr/rrc_nr.cc | 139 +++++++++++++++++- srsue/src/stack/rrc_nr/rrc_nr_procedures.cc | 54 +++++++ srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc | 52 +++++++ 5 files changed, 272 insertions(+), 4 deletions(-) diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr.h b/srsue/hdr/stack/rrc_nr/rrc_nr.h index 7bd8ca7c3..2c480d58a 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr.h @@ -136,12 +136,17 @@ public: private: // parsers void decode_pdu_bcch_dlsch(srsran::unique_byte_buffer_t pdu); + void decode_dl_ccch(srsran::unique_byte_buffer_t pdu); // senders void send_setup_request(srsran::nr_establishment_cause_t cause); + void send_con_setup_complete(srsran::unique_byte_buffer_t nas_msg); void send_ul_info_transfer(srsran::unique_byte_buffer_t nas_msg); void send_ul_ccch_msg(const asn1::rrc_nr::ul_ccch_msg_s& msg); + void send_ul_dcch_msg(uint32_t lcid, const asn1::rrc_nr::ul_dcch_msg_s& msg); + // helpers - void handle_sib1(const asn1::rrc_nr::sib1_s sib1); + void handle_sib1(const asn1::rrc_nr::sib1_s& sib1); + bool handle_rrc_setup(const asn1::rrc_nr::rrc_setup_s& setup); srsran::task_sched_handle task_sched; struct cmd_msg_t { @@ -186,6 +191,8 @@ private: const static char* rrc_nr_state_text[RRC_NR_STATE_N_ITEMS]; rrc_nr_state_t state = RRC_NR_STATE_IDLE; + uint8_t transaction_id = 0; + // Stores the state of the PHY configuration setting enum { PHY_CFG_STATE_NONE = 0, @@ -234,10 +241,12 @@ private: // RRC procedures enum class cell_search_result_t { changed_cell, same_cell, no_cell }; class cell_selection_proc; + class connection_setup_proc; class connection_reconf_no_ho_proc; class setup_request_proc; srsran::proc_t cell_selector; + srsran::proc_t conn_setup_proc; srsran::proc_t conn_recfg_proc; srsran::proc_t setup_req_proc; diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h b/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h index 8980c81d1..2996bdc4b 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h @@ -77,6 +77,26 @@ private: srsran::proc_future_t serv_cfg_fut; }; +class rrc_nr::connection_setup_proc +{ +public: + explicit connection_setup_proc(rrc_nr& parent_); + srsran::proc_outcome_t init(const asn1::rrc_nr::radio_bearer_cfg_s radio_bearer_cfg_, + const asn1::rrc_nr::cell_group_cfg_s cell_group_, + srsran::unique_byte_buffer_t dedicated_info_nas_); + srsran::proc_outcome_t step() { return srsran::proc_outcome_t::yield; } + static const char* name() { return "Connection Setup"; } + srsran::proc_outcome_t react(const bool& config_complete); + void then(const srsran::proc_state_t& result); + +private: + // const + rrc_nr& rrc_handle; + srslog::basic_logger& logger; + // args + srsran::unique_byte_buffer_t dedicated_info_nas; +}; + class rrc_nr::connection_reconf_no_ho_proc { public: diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 74ad841d0..e0024690b 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -31,6 +31,7 @@ rrc_nr::rrc_nr(srsran::task_sched_handle task_sched_) : logger(srslog::fetch_basic_logger("RRC-NR")), task_sched(task_sched_), conn_recfg_proc(*this), + conn_setup_proc(*this), setup_req_proc(*this), cell_selector(*this), meas_cells(task_sched_) @@ -209,7 +210,66 @@ void rrc_nr::run_tti(uint32_t tti) {} void rrc_nr::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) { printf("RRC received PDU\n"); + logger.debug("RX PDU, LCID: %d", lcid); + switch (static_cast(lcid)) { + case nr_srb::srb0: + decode_dl_ccch(std::move(pdu)); + break; + // case nr_srb::srb1: + // case nr_srb::srb2: + // decode_dl_dcch(lcid, std::move(pdu)); + // break; + default: + logger.error("RX PDU with invalid bearer id: %d", lcid); + break; + } +} + +void rrc_nr::decode_dl_ccch(unique_byte_buffer_t pdu) +{ + asn1::cbit_ref bref(pdu->msg, pdu->N_bytes); + asn1::rrc_nr::dl_ccch_msg_s dl_ccch_msg; + if (dl_ccch_msg.unpack(bref) != asn1::SRSASN_SUCCESS or + dl_ccch_msg.msg.type().value != dl_ccch_msg_type_c::types_opts::c1) { + logger.error(pdu->msg, pdu->N_bytes, "Failed to unpack DL-CCCH message (%d B)", pdu->N_bytes); + return; + } + log_rrc_message( + get_rb_name(srb_to_lcid(nr_srb::srb0)), Rx, pdu.get(), dl_ccch_msg, dl_ccch_msg.msg.c1().type().to_string()); + + dl_ccch_msg_type_c::c1_c_* c1 = &dl_ccch_msg.msg.c1(); + switch (dl_ccch_msg.msg.c1().type().value) { + // case dl_ccch_msg_type_c::c1_c_::types::rrc_reject: { + // // 5.3.3.8 + // rrc_conn_reject_r8_ies_s* reject_r8 = &c1->rrc_reject().crit_exts.c1().rrc_conn_reject_r8(); + // logger.info("Received ConnectionReject. Wait time: %d", reject_r8->wait_time); + // srsran::console("Received ConnectionReject. Wait time: %d\n", reject_r8->wait_time); + + // t300.stop(); + + // if (reject_r8->wait_time) { + // nas->set_barring(srsran::barring_t::all); + // t302.set(reject_r8->wait_time * 1000, [this](uint32_t tid) { timer_expired(tid); }); + // t302.run(); + // } else { + // // Perform the actions upon expiry of T302 if wait time is zero + // nas->set_barring(srsran::barring_t::none); + // start_go_idle(); + // } + // } break; + case dl_ccch_msg_type_c::c1_c_::types::rrc_setup: { + transaction_id = c1->rrc_setup().rrc_transaction_id; + rrc_setup_s rrc_setup_copy = c1->rrc_setup(); + task_sched.defer_task([this, rrc_setup_copy]() { handle_rrc_setup(rrc_setup_copy); }); + break; + } + + default: + logger.error("The provided DL-CCCH message type is not recognized"); + break; + } } + void rrc_nr::write_pdu_bcch_bch(srsran::unique_byte_buffer_t pdu) {} void rrc_nr::write_pdu_bcch_dlsch(srsran::unique_byte_buffer_t pdu) { @@ -501,6 +561,51 @@ void rrc_nr::send_ul_ccch_msg(const asn1::rrc_nr::ul_ccch_msg_s& msg) rlc->write_sdu(lcid, std::move(pdu)); } +void rrc_nr::send_ul_dcch_msg(uint32_t lcid, const ul_dcch_msg_s& msg) +{ + // Reset and reuse sdu buffer if provided + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + if (pdu == nullptr) { + logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); + return; + } + + asn1::bit_ref bref(pdu->msg, pdu->get_tailroom()); + msg.pack(bref); + bref.align_bytes_zero(); + pdu->N_bytes = (uint32_t)bref.distance_bytes(pdu->msg); + pdu->set_timestamp(); + + if (msg.msg.type() == ul_dcch_msg_type_c::types_opts::options::c1) { + log_rrc_message(get_rb_name(lcid), Tx, pdu.get(), msg, msg.msg.c1().type().to_string()); + } + + pdcp->write_sdu(lcid, std::move(pdu)); +} + +void rrc_nr::send_con_setup_complete(srsran::unique_byte_buffer_t nas_msg) +{ + logger.debug("Preparing RRC Connection Setup Complete"); + + // Prepare ConnectionSetupComplete packet + asn1::rrc_nr::ul_dcch_msg_s ul_dcch_msg; + rrc_setup_complete_ies_s* rrc_setup_complete = + &ul_dcch_msg.msg.set_c1().set_rrc_setup_complete().crit_exts.set_rrc_setup_complete(); + + ul_dcch_msg.msg.c1().rrc_setup_complete().rrc_transaction_id = transaction_id; + + rrc_setup_complete->sel_plmn_id = 1; + rrc_setup_complete->registered_amf_present = false; + rrc_setup_complete->guami_type_present = false; + rrc_setup_complete->s_nssai_list_present = false; + rrc_setup_complete->ng_minus5_g_s_tmsi_value_present = false; + + rrc_setup_complete->ded_nas_msg.resize(nas_msg->N_bytes); + memcpy(rrc_setup_complete->ded_nas_msg.data(), nas_msg->msg, nas_msg->N_bytes); + + send_ul_dcch_msg(srb_to_lcid(nr_srb::srb1), ul_dcch_msg); +} + // EUTRA-RRC interface int rrc_nr::get_eutra_nr_capabilities(srsran::byte_buffer_t* eutra_nr_caps_pdu) { @@ -1504,7 +1609,6 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) } } else { logger.warning("Reconfig with with sync not present"); - return false; } // Dedicated config @@ -1597,7 +1701,6 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) } } else { logger.warning("Option pdsch_serving_cell_cfg not present"); - return false; } if (sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present) { @@ -1611,7 +1714,6 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) } } else { logger.warning("Option csi_meas_cfg in spCellConfigDedicated not present"); - return false; } } else { @@ -1804,6 +1906,37 @@ bool rrc_nr::apply_radio_bearer_cfg(const radio_bearer_cfg_s& radio_bearer_cfg) return true; } +bool rrc_nr::handle_rrc_setup(const rrc_setup_s& setup) +{ + // Unpack masterCellGroup into container + asn1::cbit_ref bref_cg(setup.crit_exts.rrc_setup().master_cell_group.data(), + setup.crit_exts.rrc_setup().master_cell_group.size()); + + asn1::rrc_nr::cell_group_cfg_s cell_group; + if (cell_group.unpack(bref_cg) != asn1::SRSASN_SUCCESS) { + logger.error("Could not unpack master cell group config."); + return false; + } + asn1::json_writer js; + cell_group.to_json(js); + logger.debug("Containerized MasterCellGroup: %s", js.to_string().c_str()); + + // Must enter CONNECT before stopping T300 + state = RRC_NR_STATE_CONNECTED; + // t300.stop(); + // t302.stop(); + srsran::console("RRC Connected\n"); + + // defer transmission of Setup Complete until PHY reconfiguration has been completed + if (not conn_setup_proc.launch( + setup.crit_exts.rrc_setup().radio_bearer_cfg, cell_group, std::move(dedicated_info_nas))) { + logger.error("Failed to initiate connection setup procedure"); + return false; + } + callback_list.add_proc(conn_setup_proc); + return true; +} + // RLC interface void rrc_nr::max_retx_attempted() {} void rrc_nr::protocol_failure() {} diff --git a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc index 495e843da..9fec464e6 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc @@ -283,6 +283,60 @@ srsran::proc_outcome_t rrc_nr::setup_request_proc::react(const cell_selection_pr } } +/****************************************** + * Connection Setup Procedure + *****************************************/ + +// Simple procedure mainly do defer the transmission of the SetupComplete until all PHY reconfiguration are done +rrc_nr::connection_setup_proc::connection_setup_proc(srsue::rrc_nr& parent_) : + rrc_handle(parent_), logger(srslog::fetch_basic_logger("RRC")) +{} + +srsran::proc_outcome_t rrc_nr::connection_setup_proc::init(const asn1::rrc_nr::radio_bearer_cfg_s radio_bearer_cfg_, + const asn1::rrc_nr::cell_group_cfg_s cell_group_, + srsran::unique_byte_buffer_t dedicated_info_nas_) +{ + Info("Starting..."); + + // if (dedicated_info_nas_.get() == nullptr) { + // logger.error("Connection Setup Failed, no dedicatedInfoNAS available"); + // return proc_outcome_t::error; + // } + + dedicated_info_nas = std::move(dedicated_info_nas_); + + // Apply the Radio Bearer configuration + if (!rrc_handle.apply_radio_bearer_cfg(radio_bearer_cfg_)) { + return proc_outcome_t::error; + } + + // Apply the Cell Group configuration + if (!rrc_handle.apply_cell_group_cfg(cell_group_)) { + return proc_outcome_t::error; + } + + return proc_outcome_t::yield; +} + +srsran::proc_outcome_t rrc_nr::connection_setup_proc::react(const bool& config_complete) +{ + if (not config_complete) { + logger.error("Connection Setup Failed"); + return proc_outcome_t::error; + } + + rrc_handle.send_con_setup_complete(std::move(dedicated_info_nas)); + return proc_outcome_t::success; +} + +void rrc_nr::connection_setup_proc::then(const srsran::proc_state_t& result) +{ + if (result.is_success()) { + logger.info("Finished %s successfully", name()); + return; + } +} + /************************************** * Basic Cell Selection Procedure *************************************/ diff --git a/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc b/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc index 271533759..c4d2aa298 100644 --- a/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc +++ b/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc @@ -303,6 +303,57 @@ int rrc_write_pdu_bcch_dlsch_test() return SRSRAN_SUCCESS; } +int rrc_write_pdu_test() +{ + srslog::basic_logger& logger = srslog::fetch_basic_logger("RRC-NR"); + logger.set_level(srslog::basic_levels::debug); + logger.set_hex_dump_max_size(-1); + srsran::task_scheduler task_sched{512, 100}; + srsran::task_sched_handle task_sched_handle(&task_sched); + rrc_nr rrc_nr(task_sched_handle); + + dummy_phy dummy_phy; + dummy_mac dummy_mac; + dummy_rlc dummy_rlc; + dummy_pdcp dummy_pdcp; + dummy_gw dummy_gw; + dummy_eutra dummy_eutra; + dummy_sim dummy_sim; + dummy_stack dummy_stack; + rrc_nr_args_t rrc_nr_args; + TESTASSERT(rrc_nr.init(&dummy_phy, + &dummy_mac, + &dummy_rlc, + &dummy_pdcp, + &dummy_gw, + &dummy_eutra, + &dummy_sim, + task_sched.get_timer_handler(), + &dummy_stack, + rrc_nr_args) == SRSRAN_SUCCESS); + + uint8_t msg[] = {0x20, 0x40, 0x04, 0x05, 0x9a, 0xe0, 0x05, 0x80, 0x08, 0x8b, 0xd7, 0x63, 0x80, 0x83, 0x0f, 0x00, 0x03, + 0xa0, 0x10, 0x45, 0x41, 0xc2, 0x0a, 0x20, 0x92, 0x40, 0x0c, 0xa8, 0x00, 0x17, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x37, 0x08, 0x82, 0x00, 0x04, 0x91, 0x12, 0x50, 0x00, 0x04, 0x82, 0x00, 0x00, 0x20, 0x69, + 0x84, 0x0c, 0x55, 0x92, 0x10, 0x70, 0x00, 0x41, 0x03, 0x08, 0x14, 0x30, 0x72, 0x71, 0x02, 0x45, 0x0b, + 0x18, 0x34, 0x70, 0xf2, 0x38, 0x01, 0x98, 0x00, 0x85, 0x00, 0xc0, 0x8c, 0xc0, 0x05, 0x28, 0x06, 0x08, + 0x66, 0x00, 0x31, 0x40, 0x30, 0x63, 0x30, 0x01, 0x0a, 0x03, 0x84, 0x19, 0x80, 0x0a, 0x50, 0x1c, 0x28, + 0xcc, 0x00, 0x62, 0x80, 0xe1, 0x86, 0x60, 0x02, 0x14, 0x0b, 0x0e, 0x33, 0x00, 0x14, 0xa0, 0x58, 0x80, + 0x08, 0xc9, 0x04, 0x31, 0x20, 0x11, 0x92, 0x09, 0x62, 0x80, 0x23, 0x24, 0x14, 0xc5, 0x80, 0x46, 0x48, + 0x2d, 0x8c, 0x00, 0x8c, 0x90, 0x63, 0x1a, 0x01, 0x19, 0x20, 0xd6, 0x38, 0x02, 0x32, 0x41, 0xcc, 0x78, + 0xc8, 0x02, 0x82, 0x19, 0x01, 0x98, 0x00, 0xc5, 0x02, 0xc8, 0x8c, 0x80, 0x28, 0x25, 0x02, 0x42, 0x18, + 0x14, 0x40, 0x20, 0x91, 0x00, 0x0a, 0x41, 0x7f, 0xf4, 0xa5, 0x26, 0x31, 0x8d, 0x80}; + + srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + memcpy(pdu->msg, msg, sizeof(msg)); + pdu->N_bytes = sizeof(msg); + + rrc_nr.write_pdu(0, std::move(pdu)); + task_sched.run_pending_tasks(); + + return SRSRAN_SUCCESS; +} + int main(int argc, char** argv) { srslog::init(); @@ -311,6 +362,7 @@ int main(int argc, char** argv) TESTASSERT(rrc_nr_reconfig_test() == SRSRAN_SUCCESS); TESTASSERT(rrc_nr_conn_setup_test() == SRSRAN_SUCCESS); TESTASSERT(rrc_write_pdu_bcch_dlsch_test() == SRSRAN_SUCCESS); + TESTASSERT(rrc_write_pdu_test() == SRSRAN_SUCCESS); return SRSRAN_SUCCESS; }