diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr.h b/srsue/hdr/stack/rrc_nr/rrc_nr.h index c42ef51b9..59c21a4d6 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr.h @@ -24,6 +24,7 @@ #include "srsran/common/stack_procedure.h" #include "srsran/common/task_scheduler.h" #include "srsran/interfaces/ue_interfaces.h" +#include "srsran/interfaces/ue_nas_interfaces.h" #include "srsran/interfaces/ue_nr_interfaces.h" #include "srsran/interfaces/ue_rrc_interfaces.h" #include "srsue/hdr/stack/upper/gw.h" @@ -53,6 +54,7 @@ public: rlc_interface_rrc* rlc_, pdcp_interface_rrc* pdcp_, gw_interface_rrc* gw_, + nas_5g_interface_rrc_nr* nas_, rrc_eutra_interface_rrc_nr* rrc_eutra_, usim_interface_rrc_nr* usim_, srsran::timer_handler* timers_, @@ -138,11 +140,15 @@ private: 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); + void send_security_mode_complete(); // helpers void handle_sib1(const asn1::rrc_nr::sib1_s& sib1); bool handle_rrc_setup(const asn1::rrc_nr::rrc_setup_s& setup); void handle_rrc_reconfig(const asn1::rrc_nr::rrc_recfg_s& reconfig); + void handle_dl_info_transfer(const asn1::rrc_nr::dl_info_transfer_s& dl_info_transfer); + void handle_security_mode_command(const asn1::rrc_nr::security_mode_cmd_s& smc); + void generate_as_keys(); srsran::task_sched_handle task_sched; struct cmd_msg_t { @@ -163,6 +169,7 @@ private: rlc_interface_rrc* rlc = nullptr; pdcp_interface_rrc* pdcp = nullptr; gw_interface_rrc* gw = nullptr; + nas_5g_interface_rrc_nr* nas = nullptr; rrc_eutra_interface_rrc_nr* rrc_eutra = nullptr; usim_interface_rrc_nr* usim = nullptr; stack_interface_rrc* stack = nullptr; @@ -238,6 +245,8 @@ private: bool apply_drb_release(const uint8_t drb); bool apply_security_cfg(const asn1::rrc_nr::security_cfg_s& security_cfg); + // Security configuration + bool security_is_activated = false; srsran::as_security_config_t sec_cfg; typedef enum { mcg_srb1, en_dc_srb3, nr } reconf_initiator_t; diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 96c703c37..33767f5dd 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -44,6 +44,7 @@ int rrc_nr::init(phy_interface_rrc_nr* phy_, rlc_interface_rrc* rlc_, pdcp_interface_rrc* pdcp_, gw_interface_rrc* gw_, + nas_5g_interface_rrc_nr* nas_, rrc_eutra_interface_rrc_nr* rrc_eutra_, usim_interface_rrc_nr* usim_, srsran::timer_handler* timers_, @@ -54,6 +55,7 @@ int rrc_nr::init(phy_interface_rrc_nr* phy_, rlc = rlc_; pdcp = pdcp_; gw = gw_; + nas = nas_; mac = mac_; rrc_eutra = rrc_eutra_; usim = usim_; @@ -241,24 +243,23 @@ void rrc_nr::decode_dl_ccch(unique_byte_buffer_t pdu) 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_reject: { + // 5.3.15 + const auto& reject = c1->rrc_reject(); + srsran::console("Received RRC Reject"); + + t300.stop(); + + if (reject.crit_exts.rrc_reject().wait_time_present) { + // nas->set_barring(srsran::barring_t::all); + t302.set(reject.crit_exts.rrc_reject().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(); @@ -287,13 +288,22 @@ void rrc_nr::decode_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu) switch (dl_dcch_msg.msg.c1().type().value) { // TODO: ADD missing cases case dl_dcch_msg_type_c::c1_c_::types::rrc_recfg: { - transaction_id = c1->rrc_recfg().rrc_transaction_id; rrc_recfg_s recfg = c1->rrc_recfg(); task_sched.defer_task([this, recfg]() { handle_rrc_reconfig(recfg); }); break; } + case dl_dcch_msg_type_c::c1_c_::types::dl_info_transfer: { + dl_info_transfer_s dl_info_transfer = c1->dl_info_transfer(); + task_sched.defer_task([this, dl_info_transfer]() { handle_dl_info_transfer(dl_info_transfer); }); + break; + } + case dl_dcch_msg_type_c::c1_c_::types::security_mode_cmd: { + security_mode_cmd_s smc = c1->security_mode_cmd(); + task_sched.defer_task([this, smc]() { handle_security_mode_command(smc); }); + break; + } default: - logger.error("The provided DL-CCCH message type is not recognized or supported"); + logger.error("The provided DL-DCCH message type is not recognized or supported"); break; } } @@ -546,7 +556,35 @@ uint16_t rrc_nr::get_mnc() // Senders void rrc_nr::send_ul_info_transfer(unique_byte_buffer_t nas_msg) { - logger.warning("%s not implemented yet.", __FUNCTION__); + logger.debug("Preparing UL Info Transfer"); + + ul_dcch_msg_s ul_dcch_msg; + ul_info_transfer_ies_s* ul_info_transfer = + &ul_dcch_msg.msg.set_c1().set_ul_info_transfer().crit_exts.set_ul_info_transfer(); + + // Try to resize target buffer first + ul_info_transfer->ded_nas_msg.resize(nas_msg->N_bytes); + + // check we have enough space in target buffer + if (nas_msg->N_bytes > ul_info_transfer->ded_nas_msg.size()) { + logger.error("NAS message too big to send in UL Info transfer (%d > %d).", + nas_msg->N_bytes, + ul_info_transfer->ded_nas_msg.size()); + return; + } + + // copy message content + memcpy(ul_info_transfer->ded_nas_msg.data(), nas_msg->msg, nas_msg->N_bytes); + + // send message + send_ul_dcch_msg(srb_to_lcid(nr_srb::srb1), ul_dcch_msg); +} + +void rrc_nr::send_security_mode_complete() +{ + ul_dcch_msg_s ul_dcch_msg; + auto& smc = ul_dcch_msg.msg.set_c1().set_security_mode_complete().crit_exts.set_security_mode_complete(); + send_ul_dcch_msg(srb_to_lcid(nr_srb::srb1), ul_dcch_msg); } void rrc_nr::send_setup_request(srsran::nr_establishment_cause_t cause) @@ -1987,6 +2025,8 @@ bool rrc_nr::handle_rrc_setup(const rrc_setup_s& setup) void rrc_nr::handle_rrc_reconfig(const rrc_recfg_s& reconfig) { + transaction_id = reconfig.rrc_transaction_id; + if (not conn_recfg_proc.launch(nr, false, reconfig)) { logger.error("Unable to launch connection reconfiguration procedure"); return; @@ -1994,6 +2034,68 @@ void rrc_nr::handle_rrc_reconfig(const rrc_recfg_s& reconfig) callback_list.add_proc(conn_recfg_proc); } +void rrc_nr::handle_dl_info_transfer(const dl_info_transfer_s& dl_info_transfer) +{ + transaction_id = dl_info_transfer.rrc_transaction_id; + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + if (pdu == nullptr) { + logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); + return; + } + if (pdu->get_tailroom() < dl_info_transfer.crit_exts.dl_info_transfer().ded_nas_msg.size()) { + logger.error("DL Info Transfer too big (%d > %d)", + dl_info_transfer.crit_exts.dl_info_transfer().ded_nas_msg.size(), + pdu->get_tailroom()); + return; + } + pdu->N_bytes = dl_info_transfer.crit_exts.dl_info_transfer().ded_nas_msg.size(); + memcpy(pdu->msg, dl_info_transfer.crit_exts.dl_info_transfer().ded_nas_msg.data(), pdu->N_bytes); + nas->write_pdu(std::move(pdu)); +} + +void rrc_nr::handle_security_mode_command(const asn1::rrc_nr::security_mode_cmd_s& smc) +{ + transaction_id = smc.rrc_transaction_id; + + const auto& sec_algo_cfg = smc.crit_exts.security_mode_cmd().security_cfg_smc.security_algorithm_cfg; + sec_cfg.cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM)sec_algo_cfg.ciphering_algorithm.value; + if (sec_algo_cfg.integrity_prot_algorithm_present) { + sec_cfg.integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM)sec_algo_cfg.integrity_prot_algorithm.value; + } else { + logger.error("Missing Integrity Algorithm Config"); + } + + logger.info("Received Security Mode Command nea: %s, nia: %s", + ciphering_algorithm_id_nr_text[sec_cfg.cipher_algo], + integrity_algorithm_id_nr_text[sec_cfg.integ_algo]); + + // Generate AS security keys + generate_as_keys(); + security_is_activated = true; + + // Configure PDCP for security + uint32_t lcid = srb_to_lcid(nr_srb::srb1); + pdcp->config_security(lcid, sec_cfg); + pdcp->enable_integrity(lcid, DIRECTION_TXRX); + send_security_mode_complete(); + pdcp->enable_encryption(lcid, DIRECTION_TXRX); +} + +// Security helper used by Security Mode Command and Mobility handling routines +void rrc_nr::generate_as_keys() +{ + uint8_t k_asme[32] = {}; + // FIXME: need to add + // nas->get_k_asme(k_asme, 32); + logger.debug(k_asme, 32, "UE K_asme"); + // logger.debug("Generating K_enb with UL NAS COUNT: %d", nas->get_k_enb_count()); + // usim->generate_as_keys(k_asme, nas->get_k_enb_count(), &sec_cfg); + logger.info(sec_cfg.k_rrc_enc.data(), 32, "RRC encryption key - k_rrc_enc"); + logger.info(sec_cfg.k_rrc_int.data(), 32, "RRC integrity key - k_rrc_int"); + logger.info(sec_cfg.k_up_enc.data(), 32, "UP encryption key - k_up_enc"); +} + // RLC interface void rrc_nr::max_retx_attempted() {} void rrc_nr::protocol_failure() {} 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 91df50309..29e03fbab 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 @@ -107,6 +107,11 @@ class dummy_eutra : public rrc_eutra_interface_rrc_nr void nr_scg_failure_information(const srsran::scg_failure_cause_t cause){}; }; +class dummy_nas : public nas_5g_interface_rrc_nr +{ + int write_pdu(srsran::unique_byte_buffer_t pdu) { return SRSRAN_SUCCESS; }; +}; + class dummy_sim : public usim_interface_rrc_nr { bool generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) { return true; } @@ -128,7 +133,7 @@ int rrc_nr_cap_request_test() 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); + srsue::rrc_nr rrc_nr(task_sched_handle); srsran::byte_buffer_t caps; dummy_phy dummy_phy; @@ -136,6 +141,7 @@ int rrc_nr_cap_request_test() dummy_rlc dummy_rlc; dummy_pdcp dummy_pdcp; dummy_gw dummy_gw; + dummy_nas dummy_nas; dummy_eutra dummy_eutra; dummy_sim dummy_sim; dummy_stack dummy_stack; @@ -149,6 +155,7 @@ int rrc_nr_cap_request_test() &dummy_rlc, &dummy_pdcp, &dummy_gw, + &dummy_nas, &dummy_eutra, &dummy_sim, task_sched.get_timer_handler(), @@ -167,13 +174,14 @@ int rrc_nsa_reconfig_tdd_test() 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); + srsue::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_nas dummy_nas; dummy_eutra dummy_eutra; dummy_sim dummy_sim; dummy_stack dummy_stack; @@ -183,6 +191,7 @@ int rrc_nsa_reconfig_tdd_test() &dummy_rlc, &dummy_pdcp, &dummy_gw, + &dummy_nas, &dummy_eutra, &dummy_sim, task_sched.get_timer_handler(), @@ -266,13 +275,14 @@ int rrc_nsa_reconfig_fdd_test() 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); + srsue::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_nas dummy_nas; dummy_eutra dummy_eutra; dummy_sim dummy_sim; dummy_stack dummy_stack; @@ -282,6 +292,7 @@ int rrc_nsa_reconfig_fdd_test() &dummy_rlc, &dummy_pdcp, &dummy_gw, + &dummy_nas, &dummy_eutra, &dummy_sim, task_sched.get_timer_handler(), @@ -365,7 +376,7 @@ int rrc_nr_setup_request_test() 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); + srsue::rrc_nr rrc_nr(task_sched_handle); srsran::byte_buffer_t caps; dummy_phy dummy_phy; @@ -373,6 +384,7 @@ int rrc_nr_setup_request_test() dummy_rlc dummy_rlc; dummy_pdcp dummy_pdcp; dummy_gw dummy_gw; + dummy_nas dummy_nas; dummy_eutra dummy_eutra; dummy_sim dummy_sim; dummy_stack dummy_stack; @@ -385,6 +397,7 @@ int rrc_nr_setup_request_test() &dummy_rlc, &dummy_pdcp, &dummy_gw, + &dummy_nas, &dummy_eutra, &dummy_sim, task_sched.get_timer_handler(), @@ -406,13 +419,14 @@ int rrc_nr_sib1_decoding_test() 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); + srsue::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_nas dummy_nas; dummy_eutra dummy_eutra; dummy_sim dummy_sim; dummy_stack dummy_stack; @@ -422,6 +436,7 @@ int rrc_nr_sib1_decoding_test() &dummy_rlc, &dummy_pdcp, &dummy_gw, + &dummy_nas, &dummy_eutra, &dummy_sim, task_sched.get_timer_handler(), @@ -451,13 +466,14 @@ int rrc_nr_setup_test() 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); + srsue::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_nas dummy_nas; dummy_eutra dummy_eutra; dummy_sim dummy_sim; dummy_stack dummy_stack; @@ -467,6 +483,7 @@ int rrc_nr_setup_test() &dummy_rlc, &dummy_pdcp, &dummy_gw, + &dummy_nas, &dummy_eutra, &dummy_sim, task_sched.get_timer_handler(), @@ -502,13 +519,14 @@ int rrc_nr_reconfig_test() 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); + srsue::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_nas dummy_nas; dummy_eutra dummy_eutra; dummy_sim dummy_sim; dummy_stack dummy_stack; @@ -518,6 +536,7 @@ int rrc_nr_reconfig_test() &dummy_rlc, &dummy_pdcp, &dummy_gw, + &dummy_nas, &dummy_eutra, &dummy_sim, task_sched.get_timer_handler(), diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 3914bdc53..4680f9f0b 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -215,8 +215,17 @@ int ue_stack_lte::init(const stack_args_t& args_) mac_nr.init(mac_nr_args, phy_nr, &rlc_nr, &rrc_nr); rlc_nr.init(&pdcp_nr, &rrc_nr, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); pdcp_nr.init(&rlc_nr, &rrc_nr, gw); - rrc_nr.init( - phy_nr, &mac_nr, &rlc_nr, &pdcp_nr, gw, &rrc, usim.get(), task_sched.get_timer_handler(), this, args.rrc_nr); + rrc_nr.init(phy_nr, + &mac_nr, + &rlc_nr, + &pdcp_nr, + gw, + &nas_5g, + &rrc, + usim.get(), + task_sched.get_timer_handler(), + this, + args.rrc_nr); rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, &rrc_nr, args.rrc); args.nas_5g.ia5g = "0,1,2,3"; diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index 33695810b..fa186797a 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -78,8 +78,17 @@ int ue_stack_nr::init(const stack_args_t& args_) rrc_args.log_hex_limit = args.log.rrc_hex_limit; rrc_args.coreless.drb_lcid = 4; rrc_args.coreless.ip_addr = "192.168.1.3"; - rrc->init( - phy, mac.get(), rlc.get(), pdcp.get(), gw, nullptr, nullptr, task_sched.get_timer_handler(), this, rrc_args); + rrc->init(phy, + mac.get(), + rlc.get(), + pdcp.get(), + gw, + nullptr, + nullptr, + nullptr, + task_sched.get_timer_handler(), + this, + rrc_args); rrc->init_core_less(); running = true; start(STACK_MAIN_THREAD_PRIO);