diff --git a/lib/include/srsran/interfaces/ue_nas_interfaces.h b/lib/include/srsran/interfaces/ue_nas_interfaces.h index fa7f0f47d..e9fe56f43 100644 --- a/lib/include/srsran/interfaces/ue_nas_interfaces.h +++ b/lib/include/srsran/interfaces/ue_nas_interfaces.h @@ -39,6 +39,17 @@ public: virtual bool connection_request_completed(bool outcome) = 0; }; +class nas_5g_interface_rrc_nr +{ +public: +}; + +class nas_5g_interface_procedures +{ +public: + virtual int send_registration_request() = 0; +}; + } // namespace srsue #endif // SRSRAN_UE_NAS_INTERFACES_H diff --git a/lib/include/srsran/interfaces/ue_rrc_interfaces.h b/lib/include/srsran/interfaces/ue_rrc_interfaces.h index 96071af1d..ca1ded8a8 100644 --- a/lib/include/srsran/interfaces/ue_rrc_interfaces.h +++ b/lib/include/srsran/interfaces/ue_rrc_interfaces.h @@ -113,6 +113,10 @@ public: virtual bool is_config_pending() = 0; }; +class rrc_nr_interface_nas_5g +{ +public: +}; } // namespace srsue #endif // SRSRAN_UE_RRC_INTERFACES_H diff --git a/srsue/hdr/stack/upper/nas_5g.h b/srsue/hdr/stack/upper/nas_5g.h new file mode 100644 index 000000000..34171d605 --- /dev/null +++ b/srsue/hdr/stack/upper/nas_5g.h @@ -0,0 +1,98 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSUE_NAS_5G_H +#define SRSUE_NAS_5G_H + +#include "nas_base.h" +#include "srsran/common/buffer_pool.h" +#include "srsran/common/common.h" +#include "srsran/common/nas_pcap.h" +#include "srsran/common/security.h" +#include "srsran/common/stack_procedure.h" +#include "srsran/common/task_scheduler.h" +#include "srsran/interfaces/ue_gw_interfaces.h" +#include "srsran/interfaces/ue_nas_interfaces.h" +#include "srsran/interfaces/ue_rrc_interfaces.h" +#include "srsran/interfaces/ue_usim_interfaces.h" +#include "srsran/srslog/srslog.h" +#include "srsue/hdr/stack/upper/nas_5gmm_state.h" +#include "srsue/hdr/stack/upper/nas_config.h" + +using srsran::byte_buffer_t; + +namespace srsue { + +class nas_5g : public nas_base, public nas_5g_interface_rrc_nr, public nas_5g_interface_procedures +{ +public: + explicit nas_5g(srsran::task_sched_handle task_sched_); + virtual ~nas_5g(); + int init(usim_interface_nas* usim_, rrc_nr_interface_nas_5g* rrc_nr_, gw_interface_nas* gw_, const nas_args_t& cfg_); + void stop(); + void run_tti(); + + // Stack+RRC interface + bool is_registered(); + + // timer callback + void timer_expired(uint32_t timeout_id); + + // Stack interface + int switch_on(); + int switch_off(); + int enable_data(); + int disable_data(); + int start_service_request(); + +private: + rrc_nr_interface_nas_5g* rrc_nr = nullptr; + usim_interface_nas* usim = nullptr; + gw_interface_nas* gw = nullptr; + + bool running = false; + + nas_args_t cfg = {}; + mm5g_state_t state = {}; + + // Security + bool ia5g_caps[8] = {}; + bool ea5g_caps[8] = {}; + + // timers + srsran::task_sched_handle task_sched; + srsran::timer_handler::unique_timer t3502; // started when registration failure and the attempt counter is equal to 5 + srsran::timer_handler::unique_timer t3510; // started when transmission of REGISTRATION REQUEST message. ON EXPIRY: + // start T3511 or T3502 as specified in subclause 5.5.1.2.7 + srsran::timer_handler::unique_timer t3511; // started when registration failure due to lower layer failure + srsran::timer_handler::unique_timer t3521; // started when detach request is sent + srsran::timer_handler::unique_timer reregistration_timer; // started to trigger delayed re-attach + + // Values according to TS 24.501 Sec 10.2 + const uint32_t t3502_duration_ms = 12 * 60 * 1000; // 12m + const uint32_t t3510_duration_ms = 15 * 1000; // 15s + const uint32_t t3511_duration_ms = 10 * 1000; // 10s + const uint32_t t3521_duration_ms = 15 * 1000; // 15s + const uint32_t reregistration_timer_duration_ms = 2 * 1000; // 2s (arbitrarily chosen to delay re-attach) + + srsran::proc_manager_list_t callbacks; + + // Procedures + // Forward declartion + class registration_procedure; + + srsran::proc_t registration_proc; + + int send_registration_request(); +}; +} // namespace srsue +#endif \ No newline at end of file diff --git a/srsue/hdr/stack/upper/nas_5g_procedures.h b/srsue/hdr/stack/upper/nas_5g_procedures.h new file mode 100644 index 000000000..85ef15bcd --- /dev/null +++ b/srsue/hdr/stack/upper/nas_5g_procedures.h @@ -0,0 +1,40 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSUE_NAS_5G_PROCEDURES_H_ +#define SRSUE_NAS_5G_PROCEDURES_H_ + +#include "srsue/hdr/stack/upper/nas_5g.h" + +namespace srsue { + +/** + * @brief 5G NAS registration procedure + * + * Specified in 24 501 V16.7.0 + * 5GMM specific procedures + * 5.5.1 Registration procedure + */ +class nas_5g::registration_procedure +{ +public: + explicit registration_procedure(nas_5g_interface_procedures* parent_nas_); + srsran::proc_outcome_t init(); + srsran::proc_outcome_t step(); + static const char* name() { return "Registration Procedure"; } + +private: + nas_5g_interface_procedures* parent_nas; +}; +} // namespace srsue + +#endif // SRSUE_NAS_5G_PROCEDURES_H_ \ No newline at end of file diff --git a/srsue/hdr/stack/upper/nas_5gmm_state.h b/srsue/hdr/stack/upper/nas_5gmm_state.h new file mode 100644 index 000000000..29fb2a983 --- /dev/null +++ b/srsue/hdr/stack/upper/nas_5gmm_state.h @@ -0,0 +1,88 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSUE_NR_NAS_MM5G_STATE_H +#define SRSUE_NR_NAS_MM5G_STATE_H + +#include "srsran/srslog/srslog.h" +#include +#include + +namespace srsue { + +// 5GMM states (3GPP 24.501 v16.07.0) +class mm5g_state_t +{ +public: + enum class state_t { + null = 0, + deregistered, + registered_initiated, + registered, + deregistered_initiated, + service_request_initiated, + }; + + // 5GMM-DEREGISTERED sub-states (3GPP 24.501 v16.07.0) + enum class deregistered_substate_t { + null = 0, // This should be used when not in mm5g-DEREGISTERED + normal_service, + limited_service, + attempting_to_registration, + plmn_search, + no_supi, + no_cell_available, + e_call_inactive, + initial_registration_needed, + }; + + // 5GMM-DEREGISTERED sub-states (3GPP 24.501 v16.07.0) + enum class registered_substate_t { + null = 0, // This should be used when not in mm5g-REGISTERED + normal_service, + non_allowed_service, + attempting_registration_update, + limited_service, + plmn_search, + no_cell_available, + update_needed, + }; + + // FSM setters + void set_null(); + void set_deregistered(deregistered_substate_t substate); + void set_deregistered_initiated(); + void set_registered(registered_substate_t substate); + void set_registered_initiated(); + void set_service_request_initiated(); + + // FSM getters + state_t get_state() { return state; } + deregistered_substate_t get_deregistered_substate() { return deregistered_substate; } + registered_substate_t get_registered_substate() { return registered_substate; } + + // Text Helpers + const std::string get_full_state_text(); + +private: + std::atomic state{state_t::null}; + deregistered_substate_t deregistered_substate = deregistered_substate_t::null; + registered_substate_t registered_substate = registered_substate_t::null; + srslog::basic_logger& logger = srslog::fetch_basic_logger("NAS-5G"); +}; + +const char* mm5g_state_text(mm5g_state_t::state_t type); +const char* mm5g_deregistered_substate_text(mm5g_state_t::deregistered_substate_t type); +const char* mm5g_registered_substate_text(mm5g_state_t::registered_substate_t type); + +} // namespace srsue +#endif diff --git a/srsue/hdr/stack/upper/nas_config.h b/srsue/hdr/stack/upper/nas_config.h index 1836b7fce..179b0f7fa 100644 --- a/srsue/hdr/stack/upper/nas_config.h +++ b/srsue/hdr/stack/upper/nas_config.h @@ -34,6 +34,8 @@ public: bool force_imsi_attach; std::string eia; std::string eea; + std::string ia5g; + std::string ea5g; nas_sim_args_t sim; }; diff --git a/srsue/hdr/stack/upper/test/nas_test_common.h b/srsue/hdr/stack/upper/test/nas_test_common.h index 1af31d3c7..faa40bf51 100644 --- a/srsue/hdr/stack/upper/test/nas_test_common.h +++ b/srsue/hdr/stack/upper/test/nas_test_common.h @@ -22,6 +22,7 @@ #include "srsran/test/ue_test_interfaces.h" #include "srsue/hdr/stack/upper/gw.h" #include "srsue/hdr/stack/upper/nas.h" +#include "srsue/hdr/stack/upper/nas_5g.h" #include "srsue/hdr/stack/upper/usim.h" #include "srsue/hdr/stack/upper/usim_base.h" @@ -122,6 +123,26 @@ private: bool is_connected_flag = false; }; +class rrc_nr_dummy : public rrc_nr_interface_nas_5g +{ +public: + rrc_nr_dummy() : last_sdu_len(0) + { + plmns[0].plmn_id.from_number(mcc, mnc); + plmns[0].tac = 0xffff; + } + void init(nas_5g* nas_5g_) { nas_5g_ptr = nas_5g_; } + void write_sdu(unique_byte_buffer_t sdu) + { + last_sdu_len = sdu->N_bytes; + // printf("NAS generated SDU (len=%d):\n", sdu->N_bytes); + } + +private: + nas_5g* nas_5g_ptr; + uint32_t last_sdu_len; + nas_interface_rrc::found_plmn_t plmns[nas_interface_rrc::MAX_FOUND_PLMNS]; +}; template class test_stack_dummy : public srsue::stack_test_dummy, public stack_interface_gw, public thread { @@ -132,7 +153,11 @@ public: nas = nas_; start(-1); } - bool switch_on() { nas->switch_on(); return true; } + bool switch_on() + { + nas->switch_on(); + return true; + } void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { pdcp->write_sdu(lcid, std::move(sdu)); } bool has_active_radio_bearer(uint32_t eps_bearer_id) { return true; } @@ -158,7 +183,7 @@ public: wait_thread_finish(); } pdcp_interface_stack* pdcp = nullptr; - T* nas = nullptr; + T* nas = nullptr; std::atomic running = {false}; }; diff --git a/srsue/src/stack/upper/CMakeLists.txt b/srsue/src/stack/upper/CMakeLists.txt index 4d9f1e09f..29c26f205 100644 --- a/srsue/src/stack/upper/CMakeLists.txt +++ b/srsue/src/stack/upper/CMakeLists.txt @@ -8,7 +8,7 @@ add_subdirectory(test) -set(SOURCES nas.cc nas_emm_state.cc nas_idle_procedures.cc gw.cc usim_base.cc usim.cc tft_packet_filter.cc nas_base.cc) +set(SOURCES nas.cc nas_emm_state.cc nas_idle_procedures.cc gw.cc usim_base.cc usim.cc tft_packet_filter.cc nas_base.cc nas_5g_procedures.cc nas_5g.cc nas_5gmm_state.cc) if(HAVE_PCSC) list(APPEND SOURCES "pcsc_usim.cc") @@ -17,6 +17,8 @@ endif(HAVE_PCSC) add_library(srsue_upper STATIC ${SOURCES}) target_link_libraries(srsue_upper ${ATOMIC_LIBS} srsran_asn1) +target_link_libraries(srsue_upper nas_5g_msg) + if(HAVE_PCSC) target_link_libraries(srsue_upper ${PCSCLITE_LIBRARY}) endif(HAVE_PCSC) \ No newline at end of file diff --git a/srsue/src/stack/upper/nas_5g.cc b/srsue/src/stack/upper/nas_5g.cc new file mode 100644 index 000000000..97718fc75 --- /dev/null +++ b/srsue/src/stack/upper/nas_5g.cc @@ -0,0 +1,236 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsue/hdr/stack/upper/nas_5g.h" +#include "srsran/asn1/nas_5g_ies.h" +#include "srsran/asn1/nas_5g_msg.h" +#include "srsran/common/bcd_helpers.h" +#include "srsran/common/security.h" +#include "srsran/common/standard_streams.h" +#include "srsran/common/string_helpers.h" +#include "srsran/interfaces/ue_gw_interfaces.h" +#include "srsran/interfaces/ue_rrc_interfaces.h" +#include "srsran/interfaces/ue_usim_interfaces.h" +#include "srsue/hdr/stack/upper/nas_5g_procedures.h" + +#include +#include +#include +#include + +using namespace srsran; +using namespace srsran::nas_5g; + +namespace srsue { + +/********************************************************************* + * NAS 5G (NR) + ********************************************************************/ + +nas_5g::nas_5g(srsran::task_sched_handle task_sched_) : + nas_base("NAS-5G"), + task_sched(task_sched_), + t3502(task_sched_.get_unique_timer()), + t3510(task_sched_.get_unique_timer()), + t3511(task_sched_.get_unique_timer()), + t3521(task_sched_.get_unique_timer()), + reregistration_timer(task_sched_.get_unique_timer()), + registration_proc(this) +{ + // Configure timers + t3502.set(t3502_duration_ms, [this](uint32_t tid) { timer_expired(tid); }); + t3510.set(t3510_duration_ms, [this](uint32_t tid) { timer_expired(tid); }); + t3511.set(t3511_duration_ms, [this](uint32_t tid) { timer_expired(tid); }); + t3521.set(t3521_duration_ms, [this](uint32_t tid) { timer_expired(tid); }); + reregistration_timer.set(reregistration_timer_duration_ms, [this](uint32_t tid) { timer_expired(tid); }); +} + +nas_5g::~nas_5g() {} + +void nas_5g::stop() +{ + running = false; +} + +int nas_5g::init(usim_interface_nas* usim_, + rrc_nr_interface_nas_5g* rrc_nr_, + gw_interface_nas* gw_, + const nas_args_t& cfg_) +{ + usim = usim_; + rrc_nr = rrc_nr_; + gw = gw_; + cfg = cfg_; + + // parse and sanity check EIA list + if (parse_security_algorithm_list(cfg_.ia5g, ia5g_caps) != SRSRAN_SUCCESS) { + logger.warning("Failed to parse integrity algorithm list: Defaulting to 5G-EI1-128, 5G-EI2-128, 5G-EI3-128"); + ia5g_caps[0] = false; + ia5g_caps[1] = true; + ia5g_caps[2] = true; + ia5g_caps[3] = true; + } + + // parse and sanity check EEA list + if (parse_security_algorithm_list(cfg_.ea5g, ea5g_caps) != SRSRAN_SUCCESS) { + logger.warning( + "Failed to parse encryption algorithm list: Defaulting to 5G-EA0, 5G-EA1-128, 5G-EA2-128, 5G-EA3-128"); + ea5g_caps[0] = true; + ea5g_caps[1] = true; + ea5g_caps[2] = true; + ea5g_caps[3] = true; + } + + running = true; + return SRSRAN_SUCCESS; +} + +void nas_5g::run_tti() +{ + // Process PLMN selection ongoing procedures + callbacks.run(); + + // Transmit intiating messages if necessary + switch (state.get_state()) { + case mm5g_state_t::state_t::deregistered: + // TODO Make sure cell selection is finished after transitioning from another state (if required) + // Make sure the RRC is finished transitioning to RRC Idle + if (reregistration_timer.is_running()) { + logger.debug("Waiting for re-attach timer to expire to attach again."); + return; + } + switch (state.get_deregistered_substate()) { + case mm5g_state_t::deregistered_substate_t::plmn_search: + case mm5g_state_t::deregistered_substate_t::normal_service: + case mm5g_state_t::deregistered_substate_t::initial_registration_needed: + registration_proc.launch(); + break; + case mm5g_state_t::deregistered_substate_t::attempting_to_registration: + case mm5g_state_t::deregistered_substate_t::no_supi: + case mm5g_state_t::deregistered_substate_t::no_cell_available: + case mm5g_state_t::deregistered_substate_t::e_call_inactive: + logger.debug("Attempting to registration (not implemented) %s", state.get_full_state_text().c_str()); + default: + break; + } + case mm5g_state_t::state_t::registered: + break; + case mm5g_state_t::state_t::deregistered_initiated: + logger.debug("UE detaching..."); + break; + default: + break; + } +} + +/******************************************************************************* + * Senders + ******************************************************************************/ + +int nas_5g::send_registration_request() +{ + 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 registration request"); + + nas_5gs_msg nas_msg; + registration_request_t& reg_req = nas_msg.set_registration_request(); + + reg_req.registration_type_5gs.follow_on_request_bit = + registration_type_5gs_t::follow_on_request_bit_type_::options::no_follow_on_request_pending; + reg_req.registration_type_5gs.registration_type = + registration_type_5gs_t::registration_type_type_::options::initial_registration; + mobile_identity_5gs_t::suci_s& suci = reg_req.mobile_identity_5gs.set_suci(); + suci.supi_format = mobile_identity_5gs_t::suci_s::supi_format_type_::options::imsi; + mcc_to_bytes(0x0, suci.mcc.data()); + uint8_t mnc_len; + mnc_to_bytes(0x0, suci.mnc.data(), &mnc_len); + suci.scheme_output.resize(15); + usim->get_imsi_vec(suci.scheme_output.data(), 15); + logger.info("Requesting IMSI attach (IMSI=%s)", usim->get_imsi_str().c_str()); + + if (nas_msg.pack(pdu) != SRSASN_SUCCESS) { + logger.error("Failed to pack registration request"); + return SRSRAN_ERROR; + } + + if (pcap != nullptr) { + pcap->write_nas(pdu.get()->msg, pdu.get()->N_bytes); + } + + // start T3510 + logger.debug("Starting T3410. Timeout in %d ms.", t3510.duration()); + t3510.run(); + + state.set_registered_initiated(); + + return SRSRAN_SUCCESS; +} + +/******************************************************************************* + * UE Stack and RRC common Interface + ******************************************************************************/ +bool nas_5g::is_registered() +{ + return state.get_state() == mm5g_state_t::state_t::registered; +} + +/******************************************************************************* + * NAS Timers + ******************************************************************************/ +void nas_5g::timer_expired(uint32_t timeout_id) +{ + // TODO +} + +/******************************************************************************* + * UE Stack Interface + ******************************************************************************/ +int nas_5g::switch_on() +{ + logger.info("Switching on"); + state.set_deregistered(mm5g_state_t::deregistered_substate_t::plmn_search); + return SRSRAN_SUCCESS; +} + +int nas_5g::switch_off() +{ + logger.info("Switching off"); + // TODO + return SRSRAN_SUCCESS; +} + +int nas_5g::enable_data() +{ + logger.info("Enabling data services"); + return switch_on(); +} + +int nas_5g::disable_data() +{ + logger.info("Disabling data services"); + // TODO + return SRSRAN_SUCCESS; +} + +int nas_5g::start_service_request() +{ + logger.info("Service Request"); + // TODO + return SRSRAN_SUCCESS; +} + +} // namespace srsue \ No newline at end of file diff --git a/srsue/src/stack/upper/nas_5g_procedures.cc b/srsue/src/stack/upper/nas_5g_procedures.cc new file mode 100644 index 000000000..bf2b80e2d --- /dev/null +++ b/srsue/src/stack/upper/nas_5g_procedures.cc @@ -0,0 +1,38 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsue/hdr/stack/upper/nas_5g_procedures.h" + +#include +#include +#include +#include + +using namespace srsran; + +namespace srsue { + +nas_5g::registration_procedure::registration_procedure(nas_5g_interface_procedures* parent_nas_) : + parent_nas(parent_nas_) +{} + +srsran::proc_outcome_t nas_5g::registration_procedure::init() +{ + parent_nas->send_registration_request(); + return srsran::proc_outcome_t::yield; +} +srsran::proc_outcome_t nas_5g::registration_procedure::step() +{ + return srsran::proc_outcome_t::success; +} + +} // namespace srsue \ No newline at end of file diff --git a/srsue/src/stack/upper/nas_5gmm_state.cc b/srsue/src/stack/upper/nas_5gmm_state.cc new file mode 100644 index 000000000..cc8ba316e --- /dev/null +++ b/srsue/src/stack/upper/nas_5gmm_state.cc @@ -0,0 +1,149 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ +#include "srsue/hdr/stack/upper/nas_5gmm_state.h" + +namespace srsue { + +// FSM setters +void mm5g_state_t::set_null() +{ + state = state_t::null; + deregistered_substate = deregistered_substate_t::null; + registered_substate = registered_substate_t::null; + logger.debug("Changed to mm5g state: %s", get_full_state_text().c_str()); +} + +void mm5g_state_t::set_deregistered(deregistered_substate_t substate) +{ + state = state_t::deregistered; + deregistered_substate = substate; + registered_substate = registered_substate_t::null; + logger.debug("Changed to mm5g state: %s", get_full_state_text().c_str()); +} + +void mm5g_state_t::set_deregistered_initiated() +{ + state = state_t::deregistered_initiated; + deregistered_substate = deregistered_substate_t::null; + registered_substate = registered_substate_t::null; + logger.debug("Changed to mm5g state: %s", get_full_state_text().c_str()); +} + +void mm5g_state_t::set_registered(registered_substate_t substate) +{ + state = state_t::registered; + deregistered_substate = deregistered_substate_t::null; + registered_substate = substate; + logger.debug("Changed to mm5g state: %s", get_full_state_text().c_str()); +} + +void mm5g_state_t::set_registered_initiated() +{ + state = state_t::registered_initiated; + deregistered_substate = deregistered_substate_t::null; + registered_substate = registered_substate_t::null; + logger.debug("Changed to mm5g state: %s", get_full_state_text().c_str()); +} + +void mm5g_state_t::set_service_request_initiated() +{ + state = state_t::service_request_initiated; + deregistered_substate = deregistered_substate_t::null; + registered_substate = registered_substate_t::null; + logger.debug("Changed to mm5g state: %s", get_full_state_text().c_str()); +} + +const std::string mm5g_state_t::get_full_state_text() +{ + if (state == state_t::deregistered) { + return mm5g_state_text(state) + std::string(", with substate ") + + mm5g_deregistered_substate_text(deregistered_substate); + } else if (state == state_t::registered) { + return mm5g_state_text(state) + std::string(", with substate ") + + mm5g_registered_substate_text(registered_substate); + } else { + return mm5g_state_text(state); + } + return std::string("Invalid State"); +} + +/* + * Logging helper functions + */ +const char* mm5g_state_text(mm5g_state_t::state_t type) +{ + switch (type) { + case mm5g_state_t::state_t::null: + return "NULL"; + case mm5g_state_t::state_t::deregistered: + return "DEREGISTERED"; + case mm5g_state_t::state_t::registered_initiated: + return "REGISTERED-INITIATED"; + case mm5g_state_t::state_t::registered: + return "REGISTERED"; + case mm5g_state_t::state_t::deregistered_initiated: + return "DEREGISTERED-INITIATED"; + case mm5g_state_t::state_t::service_request_initiated: + return "SERVICE-REQUEST-INITIATED"; + } + return "INVALID"; +} + +const char* mm5g_deregistered_substate_text(mm5g_state_t::deregistered_substate_t type) +{ + switch (type) { + case mm5g_state_t::deregistered_substate_t::null: + return "NULL"; + case mm5g_state_t::deregistered_substate_t::normal_service: + return "NORMAL-SERVICE"; + case mm5g_state_t::deregistered_substate_t::limited_service: + return "LIMITED-SERVICE"; + case mm5g_state_t::deregistered_substate_t::attempting_to_registration: + return "ATTEMPTING-TO-REGISTRATION"; + case mm5g_state_t::deregistered_substate_t::plmn_search: + return "PLMN-SEARCH"; + case mm5g_state_t::deregistered_substate_t::no_supi: + return "NO-SUPI"; + case mm5g_state_t::deregistered_substate_t::no_cell_available: + return "NO-CELL-AVAILABLE"; + case mm5g_state_t::deregistered_substate_t::e_call_inactive: + return "eCALL-INACTIVE"; + case mm5g_state_t::deregistered_substate_t::initial_registration_needed: + return "ATTACH-NEEDED"; + } + return "INVALID"; +} + +const char* mm5g_registered_substate_text(mm5g_state_t::registered_substate_t type) +{ + switch (type) { + case mm5g_state_t::registered_substate_t::null: + return "NULL"; + case mm5g_state_t::registered_substate_t::normal_service: + return "NORMAL-SERVICE"; + case mm5g_state_t::registered_substate_t::non_allowed_service: + return "NON-ALLOWED-SERVICE"; + case mm5g_state_t::registered_substate_t::attempting_registration_update: + return "ATTEMPTING-REGISTRATION-UPDATE"; + case mm5g_state_t::registered_substate_t::limited_service: + return "LIMITED-SERVICE"; + case mm5g_state_t::registered_substate_t::plmn_search: + return "PLMN-SEARCH"; + case mm5g_state_t::registered_substate_t::no_cell_available: + return "NO-CELL-AVAILABLE"; + case mm5g_state_t::registered_substate_t::update_needed: + return "UPDATE-NEEDED"; + } + return "INVALID"; +} + +} // namespace srsue diff --git a/srsue/src/stack/upper/test/CMakeLists.txt b/srsue/src/stack/upper/test/CMakeLists.txt index 56dc8c469..8ba97816a 100644 --- a/srsue/src/stack/upper/test/CMakeLists.txt +++ b/srsue/src/stack/upper/test/CMakeLists.txt @@ -19,6 +19,10 @@ add_executable(nas_test nas_test.cc) target_link_libraries(nas_test srsue_upper srsran_common srsran_phy rrc_asn1 srsran_asn1) add_test(nas_test nas_test) +add_executable(nas_5g_test nas_5g_test.cc) +target_link_libraries(nas_5g_test srsue_upper srsran_phy rrc_asn1) +add_test(nas_5g_test nas_5g_test) + add_executable(gw_test gw_test.cc) target_link_libraries(gw_test srsue_upper srsran_common srsran_phy) add_test(gw_test gw_test) diff --git a/srsue/src/stack/upper/test/nas_5g_test.cc b/srsue/src/stack/upper/test/nas_5g_test.cc new file mode 100644 index 000000000..8556e326a --- /dev/null +++ b/srsue/src/stack/upper/test/nas_5g_test.cc @@ -0,0 +1,108 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/common/bcd_helpers.h" +#include "srsran/common/test_common.h" +#include "srsran/common/tsan_options.h" +#include "srsran/interfaces/ue_pdcp_interfaces.h" +#include "srsran/srslog/srslog.h" +#include "srsran/test/ue_test_interfaces.h" +#include "srsue/hdr/stack/upper/gw.h" +#include "srsue/hdr/stack/upper/nas_5g.h" +#include "srsue/hdr/stack/upper/test/nas_test_common.h" + +using namespace srsue; +using namespace srsran; + +#define HAVE_PCAP 0 + +int amf_attach_request_test(srsran::nas_pcap* pcap) +{ + int ret = SRSRAN_ERROR; + + rrc_nr_dummy rrc_nr_dummy; + pdcp_dummy pdcp_dummy; + + srsue::usim usim(srslog::fetch_basic_logger("USIM")); + usim_args_t args; + args.mode = "soft"; + args.algo = "xor"; + args.imei = "353490069873319"; + args.imsi = "001010123456789"; + args.k = "00112233445566778899aabbccddeeff"; + args.op = "63BFA50EE6523365FF14C1F45F88737D"; + usim.init(&args); + + nas_args_t nas_cfg; + nas_cfg.force_imsi_attach = true; + nas_cfg.apn_name = "test123"; + nas_cfg.ia5g = "0,1,2,3"; + nas_cfg.ea5g = "0,1,2,3"; + + test_stack_dummy stack(&pdcp_dummy); + srsue::nas_5g nas_5g(&stack.task_sched); + srsue::gw gw; + + if (pcap != nullptr) { + nas_5g.start_pcap(pcap); + } + + gw_args_t gw_args; + gw_args.tun_dev_name = "tun0"; + gw_args.log.gw_level = "debug"; + gw_args.log.gw_hex_limit = 100000; + + gw.init(gw_args, &stack); + stack.init(&nas_5g); + + nas_5g.init(&usim, &rrc_nr_dummy, &gw, nas_cfg); + rrc_nr_dummy.init(&nas_5g); + + // trigger test + stack.switch_on(); + stack.stop(); + + gw.stop(); + ret = SRSRAN_SUCCESS; + + return ret; +} + +int main(int argc, char** argv) +{ + // Setup logging. + auto& rrc_logger = srslog::fetch_basic_logger("RRC", false); + rrc_logger.set_level(srslog::basic_levels::debug); + rrc_logger.set_hex_dump_max_size(100000); + auto& nas_logger = srslog::fetch_basic_logger("NAS", false); + nas_logger.set_level(srslog::basic_levels::debug); + nas_logger.set_hex_dump_max_size(100000); + auto& usim_logger = srslog::fetch_basic_logger("USIM", false); + usim_logger.set_level(srslog::basic_levels::debug); + usim_logger.set_hex_dump_max_size(100000); + auto& gw_logger = srslog::fetch_basic_logger("GW", false); + gw_logger.set_level(srslog::basic_levels::debug); + gw_logger.set_hex_dump_max_size(100000); + + // Start the log backend. + srslog::init(); +#if HAVE_PCAP + srsran::nas_pcap pcap; + pcap.open("nas_5g_test.pcap", 0, srsran::srsran_rat_t::nr); + TESTASSERT(amf_attach_request_test(&pcap) == SRSRAN_SUCCESS); + pcap.close(); +#else + TESTASSERT(amf_attach_request_test(nullptr) == SRSRAN_SUCCESS); +#endif // HAVE_PCAP + + return SRSRAN_SUCCESS; +}