diff --git a/CMakeLists.txt b/CMakeLists.txt index db948d4c5..06ec93a72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,8 +411,8 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") if(FORCE_32BIT) - ADD_C_COMPILER_FLAG_IF_AVAILABLE("-m32" HAVE_WNO_UNUSED_BUT_SET_VARIABLE) - ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-m32" HAVE_WNO_UNUSED_BUT_SET_VARIABLE) + ADD_C_COMPILER_FLAG_IF_AVAILABLE("-m32" HAVE_M32) + ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-m32" HAVE_M32) set(CMAKE_SHARED_LINKER_FLAGS "-m32") endif(FORCE_32BIT) diff --git a/lib/include/srsran/common/bearer_manager.h b/lib/include/srsran/common/bearer_manager.h index 20931e4e9..849c2e7b8 100644 --- a/lib/include/srsran/common/bearer_manager.h +++ b/lib/include/srsran/common/bearer_manager.h @@ -27,8 +27,8 @@ #include "srsran/common/rwlock_guard.h" #include "srsran/srslog/srslog.h" #include -#include #include +#include namespace srsran { @@ -148,6 +148,7 @@ public: using radio_bearer_t = srsran::detail::ue_bearer_manager_impl::radio_bearer_t; enb_bearer_manager(); + ~enb_bearer_manager(); /// Multi-user interface (see comments above) void add_eps_bearer(uint16_t rnti, uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid); diff --git a/lib/include/srsran/interfaces/gnb_ngap_interfaces.h b/lib/include/srsran/interfaces/gnb_ngap_interfaces.h index 5ef04b827..3bcf20daf 100644 --- a/lib/include/srsran/interfaces/gnb_ngap_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_ngap_interfaces.h @@ -53,12 +53,12 @@ public: srsran::const_byte_span pdu, uint32_t m_tmsi) = 0; - virtual void write_pdu(uint16_t rnti, srsran::const_byte_span pdu) = 0; - virtual bool user_exists(uint16_t rnti) = 0; - virtual void user_mod(uint16_t old_rnti, uint16_t new_rnti) = 0; - virtual bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) = 0; - virtual bool is_amf_connected() = 0; - virtual void ue_notify_rrc_reconf_complete(uint16_t rnti, bool outcome) = 0; + virtual void write_pdu(uint16_t rnti, srsran::const_byte_span pdu) = 0; + virtual bool user_exists(uint16_t rnti) = 0; + virtual void user_mod(uint16_t old_rnti, uint16_t new_rnti) = 0; + virtual void user_release_request(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) = 0; + virtual bool is_amf_connected() = 0; + virtual void ue_notify_rrc_reconf_complete(uint16_t rnti, bool outcome) = 0; }; } // namespace srsenb diff --git a/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h b/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h index d3a360c00..41694356e 100644 --- a/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_rrc_nr_interfaces.h @@ -35,10 +35,11 @@ public: virtual int ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap_nr::ue_security_cap_s& caps) = 0; virtual int start_security_mode_procedure(uint16_t rnti, srsran::unique_byte_buffer_t nas_pdu) = 0; virtual int - establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) = 0; - virtual int allocate_lcid(uint16_t rnti) = 0; - virtual int release_bearers(uint16_t rnti) = 0; - virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0; + establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) = 0; + virtual int allocate_lcid(uint16_t rnti) = 0; + virtual int release_bearers(uint16_t rnti) = 0; + virtual void release_user(uint16_t rnti) = 0; + virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0; }; } // namespace srsenb diff --git a/lib/include/srsran/interfaces/phy_common_interface.h b/lib/include/srsran/interfaces/phy_common_interface.h index 346a3a8a7..219267da6 100644 --- a/lib/include/srsran/interfaces/phy_common_interface.h +++ b/lib/include/srsran/interfaces/phy_common_interface.h @@ -28,7 +28,7 @@ namespace srsran { /** - * @brief Descibes a physical layer common interface + * @brief Describes a physical layer common interface */ class phy_common_interface { diff --git a/lib/include/srsran/phy/utils/vector.h b/lib/include/srsran/phy/utils/vector.h index 4baab6f12..cf5b0825a 100644 --- a/lib/include/srsran/phy/utils/vector.h +++ b/lib/include/srsran/phy/utils/vector.h @@ -171,6 +171,9 @@ SRSRAN_API void srsran_vec_sub_ccc(const cf_t* x, const cf_t* y, cf_t* z, const SRSRAN_API void srsran_vec_sub_sss(const int16_t* x, const int16_t* y, int16_t* z, const uint32_t len); SRSRAN_API void srsran_vec_sub_bbb(const int8_t* x, const int8_t* y, int8_t* z, const uint32_t len); +/* sum a scalar to all elements of a vector */ +SRSRAN_API void srsran_vec_sc_sum_fff(const float* x, float h, float* z, uint32_t len); + /* scalar product */ SRSRAN_API void srsran_vec_sc_prod_cfc(const cf_t* x, const float h, cf_t* z, const uint32_t len); SRSRAN_API void srsran_vec_sc_prod_fcc(const float* x, const cf_t h, cf_t* z, const uint32_t len); diff --git a/lib/include/srsran/phy/utils/vector_simd.h b/lib/include/srsran/phy/utils/vector_simd.h index d59de219e..d379dba12 100644 --- a/lib/include/srsran/phy/utils/vector_simd.h +++ b/lib/include/srsran/phy/utils/vector_simd.h @@ -48,6 +48,8 @@ SRSRAN_API void srsran_vec_add_fff_simd(const float* x, const float* y, float* z SRSRAN_API void srsran_vec_sub_fff_simd(const float* x, const float* y, float* z, int len); +SRSRAN_API void srsran_vec_sc_sum_fff_simd(const float* x, float h, float* z, int len); + /* SIMD Vector Scalar Product */ SRSRAN_API void srsran_vec_sc_prod_cfc_simd(const cf_t* x, const float h, cf_t* y, const int len); diff --git a/lib/src/common/bearer_manager.cc b/lib/src/common/bearer_manager.cc index 1b4f1ce0c..5ee4d1d21 100644 --- a/lib/src/common/bearer_manager.cc +++ b/lib/src/common/bearer_manager.cc @@ -122,13 +122,15 @@ namespace srsenb { enb_bearer_manager::enb_bearer_manager() : logger(srslog::fetch_basic_logger("STCK", false)) {} +enb_bearer_manager::~enb_bearer_manager() {} + void enb_bearer_manager::add_eps_bearer(uint16_t rnti, uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) { auto user_it = users_map.find(rnti); if (user_it == users_map.end()) { // add empty bearer map // users_map.emplace( ) returns pair - auto p = users_map.emplace( rnti, srsran::detail::ue_bearer_manager_impl{}); + auto p = users_map.emplace(rnti, srsran::detail::ue_bearer_manager_impl{}); if (!p.second) { logger.error("Bearers: Unable to add a new bearer map for rnti=0x%x", rnti); return; diff --git a/lib/src/common/phy_cfg_nr.cc b/lib/src/common/phy_cfg_nr.cc index 92573857e..d3c149b58 100644 --- a/lib/src/common/phy_cfg_nr.cc +++ b/lib/src/common/phy_cfg_nr.cc @@ -46,7 +46,8 @@ srsran_dci_cfg_nr_t phy_cfg_nr_t::get_dci_cfg() const // Iterate all configured formats for (uint32_t j = 0; j < pdcch.search_space[i].nof_formats; j++) { - if (pdcch.search_space[i].type == srsran_search_space_type_common_3 && + if ((pdcch.search_space[i].type == srsran_search_space_type_common_3 or + pdcch.search_space[i].type == srsran_search_space_type_common_1) && pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_0) { dci_cfg.monitor_common_0_0 = true; } else if (pdcch.search_space[i].type == srsran_search_space_type_ue && diff --git a/lib/src/gtpu/gtpu.cc b/lib/src/gtpu/gtpu.cc index 3942a5ac9..c0ab90c4f 100644 --- a/lib/src/gtpu/gtpu.cc +++ b/lib/src/gtpu/gtpu.cc @@ -135,7 +135,6 @@ bool gtpu_read_ext_header(srsran::byte_buffer_t* pdu, case GTPU_EXT_HEADER_PDU_SESSION_CONTAINER: pdu->msg += GTPU_EXT_HEADER_PDU_SESSION_CONTAINER_LEN; pdu->N_bytes -= GTPU_EXT_HEADER_PDU_SESSION_CONTAINER_LEN; - logger.warning("skip parsing of GTPU_EXT_HEADER_PDU_SESSION_CONTAINER"); // TODO: Save Header Extension break; default: diff --git a/lib/src/phy/channel/test/awgn_channel_test.c b/lib/src/phy/channel/test/awgn_channel_test.c index 27505d7f5..c013dc2fd 100644 --- a/lib/src/phy/channel/test/awgn_channel_test.c +++ b/lib/src/phy/channel/test/awgn_channel_test.c @@ -77,11 +77,72 @@ static int parse_args(int argc, char** argv) return SRSRAN_SUCCESS; } +static int compare_floats(const void* a, const void* b) +{ + float arg1 = *(const float*)a; + float arg2 = *(const float*)b; + + if (arg1 < arg2) { + return -1; + } + if (arg1 > arg2) { + return 1; + } + return 0; +} + +/* + * Checks for Gaussianity with the Anderson--Darling test: if the returned statistic A2 is larger than 1 + * (and if the number of samples is larger than 100), then the Gaussianity hypothesis is rejected with a significance + * level of approximately 1% (see https://en.wikipedia.org/wiki/Anderson%E2%80%93Darling_test). + * + * x points to the vector of samples (real values and imaginary values) + * half_length is the number of complex samples + * y is a pointer to a helper vector used for temporary computations + */ +static float anderson(const float* x, uint32_t half_length, float* y) +{ +#define SQRT1_2 ((float)M_SQRT1_2) +#define CDF(a) ((1 + erff((a)*SQRT1_2)) * .5) + + uint32_t length = 2 * half_length; + float length_f = (float)length; + + // estimate mean and variance (the test works better with estimated values than with nominal ones) + float mean = srsran_vec_acc_ff(x, length); + mean /= length_f; + + srsran_vec_sc_sum_fff(x, -mean, y, length); + float variance = srsran_vec_dot_prod_fff(y, y, length); + variance /= length_f - 1; + + // standardize samples + srsran_vec_sc_prod_fff(y, 1 / sqrtf(variance), y, length); + + // sort standardized samples + qsort(y, length, sizeof(float), compare_floats); + + // compute Anderson--Darling statistic + float cdf1 = NAN; + float cdf2 = NAN; + float a2 = 0; + for (uint32_t ii = 0; ii < nof_samples; ii++) { + cdf1 = CDF(y[ii]); + cdf2 = CDF(y[length - ii - 1]); + a2 += (2.F * ii + 1) * (logf(cdf1) + log1pf(-cdf2)) + (2.F * (length - ii) - 1) * (logf(cdf2) + log1pf(-cdf1)); + } + a2 = -length_f - a2 / length_f; + a2 = a2 * (1 + (4 - 25 / length_f) / length_f); + + return a2; +} + int main(int argc, char** argv) { int ret = SRSRAN_SUCCESS; cf_t* input_buffer = NULL; cf_t* output_buffer = NULL; + float* help_buffer = NULL; uint64_t count_samples = 0; uint64_t count_us = 0; @@ -98,8 +159,9 @@ int main(int argc, char** argv) // Initialise buffers input_buffer = srsran_vec_cf_malloc(nof_samples); output_buffer = srsran_vec_cf_malloc(nof_samples); + help_buffer = srsran_vec_f_malloc(2 * nof_samples); - if (!input_buffer || !output_buffer) { + if (!input_buffer || !output_buffer || !help_buffer) { ERROR("Error: Allocating memory"); ret = SRSRAN_ERROR; goto clean_exit; @@ -162,6 +224,14 @@ int main(int argc, char** argv) ret = SRSRAN_ERROR; } + // Check for Gaussianity + float a2 = anderson((float*)output_buffer, nof_samples, help_buffer); + if ((nof_samples > 100 && a2 > 1) || !isfinite(a2)) { + printf("-- failed: A2 = %f > 1: not Gaussian\n", a2); + // TODO: use proper RNG with gaussian behaviour + // ret = SRSRAN_ERROR; + } + #ifdef ENABLE_GUI plot_scatter_setNewData(&plot_scatter, output_buffer, nof_samples); diff --git a/lib/src/phy/dft/ofdm.c b/lib/src/phy/dft/ofdm.c index 59089e0d6..df64e5b53 100644 --- a/lib/src/phy/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -81,7 +81,7 @@ static int ofdm_init_mbsfn_(srsran_ofdm_t* q, srsran_ofdm_cfg_t* cfg, srsran_dft if (q->fft_plan.size) { // Replan if it was initialised previously if (srsran_dft_replan(&q->fft_plan, q->cfg.symbol_sz)) { - ERROR("Reeplaning DFT plan"); + ERROR("Replanning DFT plan"); return SRSRAN_ERROR; } } else { @@ -94,7 +94,7 @@ static int ofdm_init_mbsfn_(srsran_ofdm_t* q, srsran_ofdm_cfg_t* cfg, srsran_dft // Reallocate temporal buffer only if the new number of resource blocks is bigger than initial if (q->cfg.nof_prb > q->max_prb) { - // Free before reallocating if allocted + // Free before reallocating if allocated if (q->tmp) { free(q->tmp); free(q->shift_buffer); @@ -562,7 +562,7 @@ void srsran_ofdm_rx_sf_ng(srsran_ofdm_t* q, cf_t* input, cf_t* output) } /* Transforms input OFDM symbols into output samples. - * Performs FFT on a each symbol and adds CP. + * Performs the FFT on each symbol and adds CP. */ static void ofdm_tx_slot(srsran_ofdm_t* q, int slot_in_sf) { diff --git a/lib/src/phy/gnb/gnb_dl.c b/lib/src/phy/gnb/gnb_dl.c index 53e82912a..b276bbc28 100644 --- a/lib/src/phy/gnb/gnb_dl.c +++ b/lib/src/phy/gnb/gnb_dl.c @@ -70,7 +70,7 @@ int srsran_gnb_dl_init(srsran_gnb_dl_t* q, cf_t* output[SRSRAN_MAX_PORTS], const return SRSRAN_ERROR; } - // Check symbol size is vlid + // Check symbol size is valid int symbol_sz = srsran_symbol_sz_from_srate(args->srate_hz, args->scs); if (symbol_sz <= 0) { ERROR("Error calculating symbol size from sampling rate of %.2f MHz and subcarrier spacing %s", diff --git a/lib/src/phy/phch/pusch_nr.c b/lib/src/phy/phch/pusch_nr.c index 6cea465d6..36598fb19 100644 --- a/lib/src/phy/phch/pusch_nr.c +++ b/lib/src/phy/phch/pusch_nr.c @@ -734,7 +734,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q, return SRSRAN_ERROR; } - // 7.3.1.1 and 7.3.1.2 + // 6.3.1.1 and 6.3.1.2 uint32_t nof_cw = 0; for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { nof_cw += grant->tb[tb].enabled ? 1 : 0; @@ -746,20 +746,23 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q, } } - // 7.3.1.3 Layer mapping + // 6.3.1.3 Layer mapping cf_t** x = q->d; if (grant->nof_layers > 1) { x = q->x; srsran_layermap_nr(q->d, nof_cw, x, grant->nof_layers, grant->nof_layers); } - // 7.3.1.4 Antenna port mapping + // 6.3.1.4 Transform precoding // ... Not implemented - // 7.3.1.5 Mapping to virtual resource blocks + // 6.3.1.5 Precoding // ... Not implemented - // 7.3.1.6 Mapping from virtual to physical resource blocks + // 6.3.1.6 Mapping to virtual resource blocks + // ... Not implemented + + // 6.3.1.7 Mapping from virtual to physical resource blocks int n = pusch_nr_put(q, cfg, grant, x[0], sf_symbols[0]); if (n < SRSRAN_SUCCESS) { ERROR("Putting NR PUSCH resources"); diff --git a/lib/src/phy/rf/CMakeLists.txt b/lib/src/phy/rf/CMakeLists.txt index 38b0de186..e56cc0832 100644 --- a/lib/src/phy/rf/CMakeLists.txt +++ b/lib/src/phy/rf/CMakeLists.txt @@ -71,28 +71,40 @@ if(RF_FOUND) list(APPEND SOURCES_RF rf_zmq_imp.c rf_zmq_imp_tx.c rf_zmq_imp_rx.c) endif (ZEROMQ_FOUND) - add_library(srsran_rf STATIC ${SOURCES_RF}) + add_library(srsran_rf_object OBJECT ${SOURCES_RF}) + set_property(TARGET srsran_rf_object PROPERTY POSITION_INDEPENDENT_CODE 1) + + add_library(srsran_rf STATIC $) + add_library(srsran_rf_shared SHARED $) + target_link_libraries(srsran_rf srsran_rf_utils srsran_phy) set_target_properties(srsran_rf PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION}) + target_link_libraries(srsran_rf_shared srsran_rf_utils srsran_phy) + set_target_properties(srsran_rf_shared PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION}) if (UHD_FOUND) target_link_libraries(srsran_rf ${UHD_LIBRARIES} ${Boost_LIBRARIES}) # Ubuntu 18.04 requires 'system' from Boost_LIBRARIES + target_link_libraries(srsran_rf_shared ${UHD_LIBRARIES} ${Boost_LIBRARIES}) endif (UHD_FOUND) if (BLADERF_FOUND) target_link_libraries(srsran_rf ${BLADERF_LIBRARIES}) + target_link_libraries(srsran_rf_shared ${BLADERF_LIBRARIES}) endif (BLADERF_FOUND) if (SOAPYSDR_FOUND AND ENABLE_SOAPYSDR) target_link_libraries(srsran_rf ${SOAPYSDR_LIBRARIES}) + target_link_libraries(srsran_rf_shared ${SOAPYSDR_LIBRARIES}) endif (SOAPYSDR_FOUND AND ENABLE_SOAPYSDR) if(SKIQ_FOUND) target_link_libraries(srsran_rf ${SKIQ_LIBRARIES} rt) + target_link_libraries(srsran_rf_shared ${SKIQ_LIBRARIES} rt) endif(SKIQ_FOUND) if (ZEROMQ_FOUND) target_link_libraries(srsran_rf ${ZEROMQ_LIBRARIES}) + target_link_libraries(srsran_rf_shared ${ZEROMQ_LIBRARIES}) add_executable(rf_zmq_test rf_zmq_test.c) target_link_libraries(rf_zmq_test srsran_rf) #add_test(rf_zmq_test rf_zmq_test) diff --git a/lib/src/phy/ue/ue_ul_nr.c b/lib/src/phy/ue/ue_ul_nr.c index e49509b96..437074ac0 100644 --- a/lib/src/phy/ue/ue_ul_nr.c +++ b/lib/src/phy/ue/ue_ul_nr.c @@ -142,12 +142,9 @@ int srsran_ue_ul_nr_encode_pusch(srsran_ue_ul_nr_t* q, // Generate signal srsran_ofdm_tx_sf(&q->ifft); - // Normalise to peak - uint32_t max_idx = srsran_vec_max_abs_ci(q->ifft.cfg.out_buffer, q->ifft.sf_sz); - float max_peak = cabsf(q->ifft.cfg.out_buffer[max_idx]); - if (isnormal(max_peak)) { - srsran_vec_sc_prod_cfc(q->ifft.cfg.out_buffer, 0.99f / max_peak, q->ifft.cfg.out_buffer, q->ifft.sf_sz); - } + // Scale iFFT output to compensate for iFFT amplification (due to FFTW implementation). + float scaling = 1 / sqrtf(q->ifft.cfg.symbol_sz); + srsran_vec_sc_prod_cfc(q->ifft.cfg.out_buffer, scaling, q->ifft.cfg.out_buffer, q->ifft.sf_sz); // Apply frequency offset if (isnormal(q->freq_offset_hz)) { diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index 0c1c69254..c97baf839 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -62,6 +62,12 @@ void srsran_vec_sub_bbb(const int8_t* x, const int8_t* y, int8_t* z, const uint3 srsran_vec_sub_bbb_simd(x, y, z, len); } +/* sum a scalar to all elements of a vector */ +void srsran_vec_sc_sum_fff(const float* x, float h, float* z, uint32_t len) +{ + srsran_vec_sc_sum_fff_simd(x, h, z, len); +} + // Noise estimation in chest_dl, interpolation void srsran_vec_sub_ccc(const cf_t* x, const cf_t* y, cf_t* z, const uint32_t len) { diff --git a/lib/src/phy/utils/vector_simd.c b/lib/src/phy/utils/vector_simd.c index 418c7293a..0cbba55a5 100644 --- a/lib/src/phy/utils/vector_simd.c +++ b/lib/src/phy/utils/vector_simd.c @@ -721,6 +721,36 @@ void srsran_vec_sub_fff_simd(const float* x, const float* y, float* z, const int } } +void srsran_vec_sc_sum_fff_simd(const float* x, float h, float* z, int len) +{ + int i = 0; + +#if SRSRAN_SIMD_F_SIZE + const simd_f_t hh = srsran_simd_f_set1(h); + if (SRSRAN_IS_ALIGNED(x) && SRSRAN_IS_ALIGNED(z)) { + for (; i < len - SRSRAN_SIMD_F_SIZE + 1; i += SRSRAN_SIMD_F_SIZE) { + simd_f_t xx = srsran_simd_f_load(&x[i]); + + simd_f_t zz = srsran_simd_f_add(xx, hh); + + srsran_simd_f_store(&z[i], zz); + } + } else { + for (; i < len - SRSRAN_SIMD_F_SIZE + 1; i += SRSRAN_SIMD_F_SIZE) { + simd_f_t xx = srsran_simd_f_loadu(&x[i]); + + simd_f_t zz = srsran_simd_f_add(xx, hh); + + srsran_simd_f_storeu(&z[i], zz); + } + } +#endif + + for (; i < len; i++) { + z[i] = x[i] + h; + } +} + cf_t srsran_vec_dot_prod_ccc_simd(const cf_t* x, const cf_t* y, const int len) { int i = 0; diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index 0617a2ae9..aac68b851 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -511,6 +511,7 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) if (header.p) { logger->info("%s Status packet requested through polling bit", parent->rb_name); do_status = true; + status_prohibit_timer.stop(); } debug_state(); @@ -640,7 +641,10 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m } if (max_len != UINT32_MAX) { - status_prohibit_timer.run(); // UINT32_MAX is used just to querry the status PDU length + // UINT32_MAX is used just to querry the status PDU length + if (status_prohibit_timer.is_valid()) { + status_prohibit_timer.run(); + } } return tmp_buf.N_bytes; } diff --git a/srsenb/hdr/stack/upper/gtpu_pdcp_adapter.h b/srsenb/hdr/stack/upper/gtpu_pdcp_adapter.h new file mode 100644 index 000000000..c34f60a55 --- /dev/null +++ b/srsenb/hdr/stack/upper/gtpu_pdcp_adapter.h @@ -0,0 +1,78 @@ +/** + * + * \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 SRSRAN_GTPU_PDCP_ADAPTER_H +#define SRSRAN_GTPU_PDCP_ADAPTER_H + +#include "srsran/common/bearer_manager.h" +#include "srsran/interfaces/enb_gtpu_interfaces.h" +#include "srsran/srslog/logger.h" + +namespace srsenb { + +class gtpu_pdcp_adapter final : public gtpu_interface_pdcp, public pdcp_interface_gtpu +{ +public: + gtpu_pdcp_adapter(srslog::basic_logger& logger_, + pdcp_interface_gtpu* pdcp_lte, + pdcp_interface_gtpu* pdcp_nr, + gtpu* gtpu_, + enb_bearer_manager& bearers_) : + logger(logger_), pdcp_lte_obj(pdcp_lte), pdcp_nr_obj(pdcp_nr), gtpu_obj(gtpu_), bearers(&bearers_) + {} + + /// Converts LCID to EPS-BearerID and sends corresponding PDU to GTPU + void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override + { + auto bearer = bearers->get_lcid_bearer(rnti, lcid); + if (not bearer.is_valid()) { + logger.error("Bearer rnti=0x%x, lcid=%d not found", rnti, lcid); + return; + } + gtpu_obj->write_pdu(rnti, bearer.eps_bearer_id, std::move(pdu)); + } + void write_sdu(uint16_t rnti, uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) override + { + auto bearer = bearers->get_radio_bearer(rnti, eps_bearer_id); + // route SDU to PDCP entity + if (bearer.rat == srsran::srsran_rat_t::lte) { + pdcp_lte_obj->write_sdu(rnti, bearer.lcid, std::move(sdu), pdcp_sn); + } else if (bearer.rat == srsran::srsran_rat_t::nr) { + pdcp_nr_obj->write_sdu(rnti, bearer.lcid, std::move(sdu), pdcp_sn); + } else { + logger.warning("Can't deliver SDU for EPS bearer %d. Dropping it.", eps_bearer_id); + } + } + std::map get_buffered_pdus(uint16_t rnti, uint32_t eps_bearer_id) override + { + auto bearer = bearers->get_radio_bearer(rnti, eps_bearer_id); + // route SDU to PDCP entity + if (bearer.rat == srsran::srsran_rat_t::lte) { + return pdcp_lte_obj->get_buffered_pdus(rnti, bearer.lcid); + } else if (bearer.rat == srsran::srsran_rat_t::nr) { + return pdcp_nr_obj->get_buffered_pdus(rnti, bearer.lcid); + } + logger.error("Bearer rnti=0x%x, eps-BearerID=%d not found", rnti, eps_bearer_id); + return {}; + } + +private: + srslog::basic_logger& logger; + gtpu* gtpu_obj = nullptr; + pdcp_interface_gtpu* pdcp_lte_obj = nullptr; + pdcp_interface_gtpu* pdcp_nr_obj = nullptr; + enb_bearer_manager* bearers = nullptr; +}; + +} // namespace srsenb + +#endif // SRSRAN_GTPU_PDCP_ADAPTER_H diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index d290957ff..56b3165b0 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -1519,6 +1519,8 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t* return SRSRAN_ERROR; } + rrc_nr_cfg_->inactivity_timeout_ms = args_->general.rrc_inactivity_timer; + // Create NR dedicated cell configuration from RRC configuration for (auto& cfg : rrc_nr_cfg_->cell_list) { cfg.phy_cell.carrier.max_mimo_layers = args_->enb.nof_ports; @@ -1548,6 +1550,9 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t* cfg.phy_cell.pdsch.rs_power = phy_cfg_->pdsch_cnfg.ref_sig_pwr; cfg.phy_cell.pdsch.p_b = phy_cfg_->pdsch_cnfg.p_b; } + rrc_nr_cfg_->enb_id = args_->enb.enb_id; + rrc_nr_cfg_->mcc = args_->stack.s1ap.mcc; + rrc_nr_cfg_->mnc = args_->stack.s1ap.mnc; // Derive cross-dependent cell params if (set_derived_nr_rrc_params(*rrc_nr_cfg_) != SRSRAN_SUCCESS) { diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index bdd96e1a8..dcb8202d6 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -188,7 +188,7 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe fmt::print("RF status: O={}, U={}, L={}\n", metrics.rf.rf_o, metrics.rf.rf_u, metrics.rf.rf_l); } - if (metrics.stack.rrc.ues.size() == 0) { + if (metrics.stack.rrc.ues.size() == 0 && metrics.nr_stack.mac.ues.size() == 0) { return; } diff --git a/srsenb/src/phy/nr/slot_worker.cc b/srsenb/src/phy/nr/slot_worker.cc index 474c533ec..780ffcac4 100644 --- a/srsenb/src/phy/nr/slot_worker.cc +++ b/srsenb/src/phy/nr/slot_worker.cc @@ -300,7 +300,7 @@ bool slot_worker::work_dl() } if (srsran_gnb_dl_base_zero(&gnb_dl) < SRSRAN_SUCCESS) { - logger.error("Error zeroeing RE grid"); + logger.error("Error zeroing RE grid"); return false; } diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index 972dbfd48..88e4d3c5b 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -22,6 +22,7 @@ #include "srsenb/hdr/stack/enb_stack_lte.h" #include "srsenb/hdr/common/rnti_pool.h" #include "srsenb/hdr/enb.h" +#include "srsenb/hdr/stack/upper/gtpu_pdcp_adapter.h" #include "srsran/interfaces/enb_metrics_interface.h" #include "srsran/interfaces/enb_x2_interfaces.h" #include "srsran/rlc/bearer_mem_pool.h" @@ -31,60 +32,6 @@ using namespace srsran; namespace srsenb { -class gtpu_pdcp_adapter final : public gtpu_interface_pdcp, public pdcp_interface_gtpu -{ -public: - gtpu_pdcp_adapter(srslog::basic_logger& logger_, - pdcp* pdcp_lte, - pdcp_interface_gtpu* pdcp_x2, - gtpu* gtpu_, - enb_bearer_manager& bearers_) : - logger(logger_), pdcp_obj(pdcp_lte), pdcp_x2_obj(pdcp_x2), gtpu_obj(gtpu_), bearers(&bearers_) - {} - - /// Converts LCID to EPS-BearerID and sends corresponding PDU to GTPU - void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override - { - auto bearer = bearers->get_lcid_bearer(rnti, lcid); - if (not bearer.is_valid()) { - logger.error("Bearer rnti=0x%x, lcid=%d not found", rnti, lcid); - return; - } - gtpu_obj->write_pdu(rnti, bearer.eps_bearer_id, std::move(pdu)); - } - void write_sdu(uint16_t rnti, uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) override - { - auto bearer = bearers->get_radio_bearer(rnti, eps_bearer_id); - // route SDU to PDCP entity - if (bearer.rat == srsran_rat_t::lte) { - pdcp_obj->write_sdu(rnti, bearer.lcid, std::move(sdu), pdcp_sn); - } else if (bearer.rat == srsran_rat_t::nr) { - pdcp_x2_obj->write_sdu(rnti, bearer.lcid, std::move(sdu), pdcp_sn); - } else { - logger.warning("Can't deliver SDU for EPS bearer %d. Dropping it.", eps_bearer_id); - } - } - std::map get_buffered_pdus(uint16_t rnti, uint32_t eps_bearer_id) override - { - auto bearer = bearers->get_radio_bearer(rnti, eps_bearer_id); - // route SDU to PDCP entity - if (bearer.rat == srsran_rat_t::lte) { - return pdcp_obj->get_buffered_pdus(rnti, bearer.lcid); - } else if (bearer.rat == srsran_rat_t::nr) { - return pdcp_x2_obj->get_buffered_pdus(rnti, bearer.lcid); - } - logger.error("Bearer rnti=0x%x, eps-BearerID=%d not found", rnti, eps_bearer_id); - return {}; - } - -private: - srslog::basic_logger& logger; - gtpu* gtpu_obj = nullptr; - pdcp* pdcp_obj = nullptr; - pdcp_interface_gtpu* pdcp_x2_obj = nullptr; - enb_bearer_manager* bearers = nullptr; -}; - enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) : thread("STACK"), mac_logger(srslog::fetch_basic_logger("MAC", log_sink)), diff --git a/srsepc/hdr/mme/nas.h b/srsepc/hdr/mme/nas.h index ba9c6c894..02b6565c7 100644 --- a/srsepc/hdr/mme/nas.h +++ b/srsepc/hdr/mme/nas.h @@ -225,6 +225,7 @@ public: /* Uplink NAS messages handling */ bool handle_attach_request(srsran::byte_buffer_t* nas_rx); + bool handle_pdn_connectivity_request(srsran::byte_buffer_t* nas_rx); bool handle_authentication_response(srsran::byte_buffer_t* nas_rx); bool handle_security_mode_complete(srsran::byte_buffer_t* nas_rx); bool handle_attach_complete(srsran::byte_buffer_t* nas_rx); @@ -246,7 +247,7 @@ public: bool pack_attach_accept(srsran::byte_buffer_t* nas_buffer); /* Security functions */ - bool integrity_check(srsran::byte_buffer_t* pdu); + bool integrity_check(srsran::byte_buffer_t* pdu, bool warn_failure = true); bool short_integrity_check(srsran::byte_buffer_t* pdu); void integrity_generate(srsran::byte_buffer_t* pdu, uint8_t* mac); void cipher_decrypt(srsran::byte_buffer_t* pdu); diff --git a/srsepc/src/mme/nas.cc b/srsepc/src/mme/nas.cc index 1408a2b57..bd22128fe 100644 --- a/srsepc/src/mme/nas.cc +++ b/srsepc/src/mme/nas.cc @@ -965,8 +965,8 @@ bool nas::handle_attach_request(srsran::byte_buffer_t* nas_rx) m_s1ap->send_downlink_nas_transport( m_ecm_ctx.enb_ue_s1ap_id, m_ecm_ctx.mme_ue_s1ap_id, nas_tx.get(), m_ecm_ctx.enb_sri); - m_logger.info("Downlink NAS: Sending Authentication Request"); - srsran::console("Downlink NAS: Sending Authentication Request\n"); + m_logger.info("DL NAS: Sending Authentication Request"); + srsran::console("DL NAS: Sending Authentication Request\n"); return true; } else { m_logger.error("Attach request from known UE"); @@ -974,6 +974,47 @@ bool nas::handle_attach_request(srsran::byte_buffer_t* nas_rx) return true; } +bool nas::handle_pdn_connectivity_request(srsran::byte_buffer_t* nas_rx) +{ + LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req = {}; + + // Get PDN connectivity request messages + LIBLTE_ERROR_ENUM err = + liblte_mme_unpack_pdn_connectivity_request_msg((LIBLTE_BYTE_MSG_STRUCT*)nas_rx->msg, &pdn_con_req); + if (err != LIBLTE_SUCCESS) { + m_logger.error("Error unpacking NAS PDN Connectivity Request. Error: %s", liblte_error_text[err]); + return false; + } + + // Send PDN connectivity reject + srsran::unique_byte_buffer_t nas_tx = srsran::make_byte_buffer(); + if (nas_tx == nullptr) { + m_logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); + return false; + } + + LIBLTE_MME_PDN_CONNECTIVITY_REJECT_MSG_STRUCT pdn_con_reject = {}; + pdn_con_reject.eps_bearer_id = pdn_con_req.eps_bearer_id; + pdn_con_reject.proc_transaction_id = pdn_con_req.proc_transaction_id; + pdn_con_reject.esm_cause = LIBLTE_MME_ESM_CAUSE_SERVICE_OPTION_NOT_SUPPORTED; + + err = liblte_mme_pack_pdn_connectivity_reject_msg(&pdn_con_reject, (LIBLTE_BYTE_MSG_STRUCT*)nas_tx.get()); + if (err != LIBLTE_SUCCESS) { + m_logger.error("Error packing PDN connectivity reject"); + srsran::console("Error packing PDN connectivity reject\n"); + return false; + } + + // Send reply to eNB + m_s1ap->send_downlink_nas_transport( + m_ecm_ctx.enb_ue_s1ap_id, m_ecm_ctx.mme_ue_s1ap_id, nas_tx.get(), m_ecm_ctx.enb_sri); + + m_logger.info("DL NAS: Sending PDN Connectivity Reject"); + srsran::console("DL NAS: Sending PDN Connectivity Reject\n"); + + return true; +} + bool nas::handle_authentication_response(srsran::byte_buffer_t* nas_rx) { LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_resp = {}; @@ -1395,8 +1436,8 @@ bool nas::pack_security_mode_command(srsran::byte_buffer_t* nas_buffer) sm_cmd.imeisv_req = LIBLTE_MME_IMEISV_REQUESTED; } - sm_cmd.nonce_ue_present = false; - sm_cmd.nonce_mme_present = false; + sm_cmd.nonce_ue_present = false; + sm_cmd.nonce_mme_present = false; uint8_t sec_hdr_type = 3; LIBLTE_ERROR_ENUM err = liblte_mme_pack_security_mode_command_msg( @@ -1773,7 +1814,7 @@ bool nas::short_integrity_check(srsran::byte_buffer_t* pdu) return true; } -bool nas::integrity_check(srsran::byte_buffer_t* pdu) +bool nas::integrity_check(srsran::byte_buffer_t* pdu, bool warn_failure) { uint8_t exp_mac[4] = {}; const uint8_t* mac = &pdu->msg[1]; @@ -1816,20 +1857,21 @@ bool nas::integrity_check(srsran::byte_buffer_t* pdu) // Check if expected mac equals the sent mac for (int i = 0; i < 4; i++) { if (exp_mac[i] != mac[i]) { - m_logger.warning("Integrity check failure. Algorithm=EIA%d", (int)m_sec_ctx.integ_algo); - m_logger.warning("UL Local: est_count=%d, old_count=%d, MAC=[%02x %02x %02x %02x], " - "Received: UL count=%d, MAC=[%02x %02x %02x %02x]", - estimated_count, - m_sec_ctx.ul_nas_count, - exp_mac[0], - exp_mac[1], - exp_mac[2], - exp_mac[3], - pdu->msg[5], - mac[0], - mac[1], - mac[2], - mac[3]); + srslog::log_channel& channel = warn_failure ? m_logger.warning : m_logger.info; + channel("Integrity check failure. Algorithm=EIA%d", (int)m_sec_ctx.integ_algo); + channel("UL Local: est_count=%d, old_count=%d, MAC=[%02x %02x %02x %02x], " + "Received: UL count=%d, MAC=[%02x %02x %02x %02x]", + estimated_count, + m_sec_ctx.ul_nas_count, + exp_mac[0], + exp_mac[1], + exp_mac[2], + exp_mac[3], + pdu->msg[5], + mac[0], + mac[1], + mac[2], + mac[3]); return false; } } diff --git a/srsepc/src/mme/s1ap_nas_transport.cc b/srsepc/src/mme/s1ap_nas_transport.cc index e4a89a8c9..0a4e220cd 100644 --- a/srsepc/src/mme/s1ap_nas_transport.cc +++ b/srsepc/src/mme/s1ap_nas_transport.cc @@ -68,18 +68,18 @@ void s1ap_nas_transport::init() m_s1ap = s1ap::get_instance(); // Init NAS args - m_nas_init.mcc = m_s1ap->m_s1ap_args.mcc; - m_nas_init.mnc = m_s1ap->m_s1ap_args.mnc; - m_nas_init.mme_code = m_s1ap->m_s1ap_args.mme_code; - m_nas_init.mme_group = m_s1ap->m_s1ap_args.mme_group; - m_nas_init.tac = m_s1ap->m_s1ap_args.tac; - m_nas_init.apn = m_s1ap->m_s1ap_args.mme_apn; - m_nas_init.dns = m_s1ap->m_s1ap_args.dns_addr; + m_nas_init.mcc = m_s1ap->m_s1ap_args.mcc; + m_nas_init.mnc = m_s1ap->m_s1ap_args.mnc; + m_nas_init.mme_code = m_s1ap->m_s1ap_args.mme_code; + m_nas_init.mme_group = m_s1ap->m_s1ap_args.mme_group; + m_nas_init.tac = m_s1ap->m_s1ap_args.tac; + m_nas_init.apn = m_s1ap->m_s1ap_args.mme_apn; + m_nas_init.dns = m_s1ap->m_s1ap_args.dns_addr; m_nas_init.full_net_name = m_s1ap->m_s1ap_args.full_net_name; m_nas_init.short_net_name = m_s1ap->m_s1ap_args.short_net_name; - m_nas_init.paging_timer = m_s1ap->m_s1ap_args.paging_timer; - m_nas_init.integ_algo = m_s1ap->m_s1ap_args.integrity_algo; - m_nas_init.cipher_algo = m_s1ap->m_s1ap_args.encryption_algo; + m_nas_init.paging_timer = m_s1ap->m_s1ap_args.paging_timer; + m_nas_init.integ_algo = m_s1ap->m_s1ap_args.integrity_algo; + m_nas_init.cipher_algo = m_s1ap->m_s1ap_args.encryption_algo; m_nas_init.request_imeisv = m_s1ap->m_s1ap_args.request_imeisv; // Init NAS interface @@ -179,17 +179,28 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(const asn1::s1ap::ul_nas_tr m_logger.error("Unhandled security header type in Uplink NAS Transport: %d", sec_hdr_type); return false; } - // Todo: Check on count mismatch of uplink count and do resync nas counter... + + // Some messages may have invalid MAC. Check wether we need to warn about MAC failures. + bool warn_integrity_fail = true; + if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY || + sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT) { + // Avoid unecessary warnings for identity response and authentication response. + liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg.get(), &pd, &msg_type); + if (msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE || msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE) { + warn_integrity_fail = false; + } + } // Check MAC if message is integrity protected if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY || - sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED || sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT || + sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED || sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT) { - mac_valid = nas_ctx->integrity_check(nas_msg.get()); - if (mac_valid == false) { - m_logger.warning("Invalid MAC message. Even if security header indicates integrity protection (Maybe: " - "Identity Response or Authentication Response)"); + mac_valid = nas_ctx->integrity_check(nas_msg.get(), warn_integrity_fail); + if (not mac_valid) { + srslog::log_channel& channel = warn_integrity_fail ? m_logger.warning : m_logger.info; + channel("Invalid MAC message. Even if security header indicates integrity protection (Maybe: " + "Identity Response or Authentication Response)"); } } @@ -317,6 +328,11 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(const asn1::s1ap::ul_nas_tr srsran::console("UL NAS: Tracking Area Update Request\n"); nas_ctx->handle_tracking_area_update_request(nas_msg.get()); break; + case LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REQUEST: + m_logger.info("UL NAS: PDN Connectivity Request"); + srsran::console("UL NAS: PDN Connectivity Request\n"); + nas_ctx->handle_pdn_connectivity_request(nas_msg.get()); + break; default: m_logger.warning("Unhandled NAS integrity protected message %s", liblte_nas_msg_type_to_string(msg_type)); srsran::console("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type)); diff --git a/srsgnb/hdr/stack/common/test/dummy_nr_classes.h b/srsgnb/hdr/stack/common/test/dummy_nr_classes.h index c2db59900..40b0c9d4a 100644 --- a/srsgnb/hdr/stack/common/test/dummy_nr_classes.h +++ b/srsgnb/hdr/stack/common/test/dummy_nr_classes.h @@ -45,7 +45,7 @@ class ngap_dummy : public ngap_interface_rrc_nr void write_pdu(uint16_t rnti, srsran::const_byte_span pdu) {} bool user_exists(uint16_t rnti) { return true; } void user_mod(uint16_t old_rnti, uint16_t new_rnti) {} - bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) { return true; } + void user_release_request(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) {} bool is_amf_connected() { return true; } void ue_notify_rrc_reconf_complete(uint16_t rnti, bool outcome) {} }; diff --git a/srsgnb/hdr/stack/gnb_stack_nr.h b/srsgnb/hdr/stack/gnb_stack_nr.h index c12226dc9..3a012877b 100644 --- a/srsgnb/hdr/stack/gnb_stack_nr.h +++ b/srsgnb/hdr/stack/gnb_stack_nr.h @@ -42,6 +42,8 @@ namespace srsenb { class ngap; class gtpu; +class enb_bearer_manager; +class gtpu_pdcp_adapter; struct gnb_stack_args_t { stack_log_args_t log; @@ -162,6 +164,9 @@ private: std::unique_ptr gtpu; // std::unique_ptr m_sdap; + std::unique_ptr bearer_manager; + std::unique_ptr gtpu_adapter; + // state std::atomic running = {false}; }; diff --git a/srsgnb/hdr/stack/mac/sched_nr_cfg.h b/srsgnb/hdr/stack/mac/sched_nr_cfg.h index 96d49d8a8..6faf5f743 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_cfg.h +++ b/srsgnb/hdr/stack/mac/sched_nr_cfg.h @@ -104,6 +104,20 @@ struct bwp_params_t { srsran::optional_vector common_cce_list; bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg_, uint32_t cc, uint32_t bwp_id); + + const prb_bitmap& used_prbs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const + { + if (used_common_prb_masks.contains(ss_id)) { + if (dci_fmt == srsran_dci_format_nr_1_0) { + return used_common_prb_masks[ss_id]; + } + } + return cached_empty_prb_mask; + } + +private: + prb_bitmap cached_empty_prb_mask; + srsran::optional_vector used_common_prb_masks; }; /// Structure packing a single cell config params, and sched args diff --git a/srsgnb/hdr/stack/mac/sched_nr_grant_allocator.h b/srsgnb/hdr/stack/mac/sched_nr_grant_allocator.h index ac86dd050..0b5cbbdf2 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_grant_allocator.h +++ b/srsgnb/hdr/stack/mac/sched_nr_grant_allocator.h @@ -71,6 +71,11 @@ struct bwp_slot_grid { bool is_dl() const { return cfg->slots[slot_idx].is_dl; } bool is_ul() const { return cfg->slots[slot_idx].is_ul; } + + prb_bitmap used_prbs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const + { + return dl_prbs.prbs() | cfg->used_prbs(ss_id, dci_fmt); + } }; struct bwp_res_grid { diff --git a/srsgnb/hdr/stack/ngap/ngap.h b/srsgnb/hdr/stack/ngap/ngap.h index b0c86297b..63b5e9af8 100644 --- a/srsgnb/hdr/stack/ngap/ngap.h +++ b/srsgnb/hdr/stack/ngap/ngap.h @@ -60,33 +60,40 @@ public: void initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, - srsran::const_byte_span pdu); + srsran::const_byte_span pdu) override; void initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, srsran::const_byte_span pdu, - uint32_t s_tmsi); + uint32_t s_tmsi) override; - void write_pdu(uint16_t rnti, srsran::const_byte_span pdu); - bool user_exists(uint16_t rnti) { return true; }; - void user_mod(uint16_t old_rnti, uint16_t new_rnti){}; - bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) { return true; }; - bool is_amf_connected(); + void write_pdu(uint16_t rnti, srsran::const_byte_span pdu) override; + bool user_exists(uint16_t rnti) override { return true; }; + void user_mod(uint16_t old_rnti, uint16_t new_rnti) override {} + + // TS 38.413 - Section 8.3.2 - UE Context Release Request + void user_release_request(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) override; + + bool is_amf_connected() override; bool send_error_indication(const asn1::ngap_nr::cause_c& cause, srsran::optional ran_ue_ngap_id = {}, srsran::optional amf_ue_ngap_id = {}); - void ue_notify_rrc_reconf_complete(uint16_t rnti, bool outcome); + void ue_notify_rrc_reconf_complete(uint16_t rnti, bool outcome) override; bool send_pdu_session_resource_setup_response(); // Stack interface bool - handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags); + handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags); void get_metrics(ngap_metrics_t& m); void get_args(ngap_args_t& args_); // PCAP void start_pcap(srsran::ngap_pcap* pcap_); + // Logging + typedef enum { Rx = 0, Tx } direction_t; + void log_ngap_message(const asn1::ngap_nr::ngap_pdu_c& msg, const direction_t dir, srsran::const_byte_span pdu); + private: static const int AMF_PORT = 38412; static const int ADDR_FAMILY = AF_INET; @@ -135,7 +142,7 @@ private: // TS 38.413 - Section 9.2.6.3 - NG Setup Failure bool handle_ng_setup_failure(const asn1::ngap_nr::ng_setup_fail_s& msg); // TS 38.413 - Section 9.2.2.5 - UE Context Release Command - bool handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg); + bool handle_ue_context_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg); // TS 38.413 - Section 9.2.2.1 - Initial Context Setup Request bool handle_initial_ctxt_setup_request(const asn1::ngap_nr::init_context_setup_request_s& msg); // TS 38.413 - Section 9.2.1.1 - PDU Session Resource Setup Request diff --git a/srsgnb/hdr/stack/ngap/ngap_ue.h b/srsgnb/hdr/stack/ngap/ngap_ue.h index 0c7511916..f1dc18eae 100644 --- a/srsgnb/hdr/stack/ngap/ngap_ue.h +++ b/srsgnb/hdr/stack/ngap/ngap_ue.h @@ -57,12 +57,15 @@ public: bool send_ue_ctxt_release_complete(); // TS 38.413 - Section 9.2.2.1 - Initial Context Setup Request bool handle_initial_ctxt_setup_request(const asn1::ngap_nr::init_context_setup_request_s& msg); + // TS 38.413 - Section 9.2.2.4 - UE Context Release Request + bool send_ue_context_release_request(asn1::ngap_nr::cause_c cause); // TS 38.413 - Section 9.2.2.5 - UE Context Release Command - bool handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg); + bool handle_ue_context_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg); // TS 38.413 - Section 9.2.1.1 - PDU Session Resource Setup Request bool handle_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg); - bool was_uectxtrelease_requested() const { return release_requested; } + /// Checks if a UE Context Release Request was already sent + bool was_ue_context_release_requested() const { return release_requested; } void notify_rrc_reconf_complete(const bool reconf_complete_outcome); ngap_ue_ctxt_t ctxt = {}; diff --git a/srsgnb/hdr/stack/ngap/ngap_ue_bearer_manager.h b/srsgnb/hdr/stack/ngap/ngap_ue_bearer_manager.h index a7617ce74..c06c2a432 100644 --- a/srsgnb/hdr/stack/ngap/ngap_ue_bearer_manager.h +++ b/srsgnb/hdr/stack/ngap/ngap_ue_bearer_manager.h @@ -65,18 +65,24 @@ public: int reset_pdu_sessions(uint16_t rnti); + using pdu_session_list_t = std::map; + const pdu_session_list_t& pdu_sessions() const { return pdu_session_list; } + private: - gtpu_interface_rrc* gtpu = nullptr; - std::map pdu_session_list; - srslog::basic_logger& logger; + gtpu_interface_rrc* gtpu = nullptr; + pdu_session_list_t pdu_session_list; + srslog::basic_logger& logger; + + std::map next_lcid_list; // Map RNTI to next LCID to be allocated - int add_gtpu_bearer(uint16_t rnti, - uint32_t pdu_session_id, - uint32_t teid_out, - asn1::bounded_bitstring<1, 160, true, true> address, - pdu_session_t::gtpu_tunnel& tunnel, // out parameter - const gtpu_interface_rrc::bearer_props* props = nullptr); - void rem_gtpu_bearer(uint16_t rnti, uint32_t pdu_session_id); + int add_gtpu_bearer(uint16_t rnti, + uint32_t pdu_session_id, + uint32_t teid_out, + asn1::bounded_bitstring<1, 160, true, true> address, + pdu_session_t::gtpu_tunnel& tunnel, // out parameter + const gtpu_interface_rrc::bearer_props* props = nullptr); + void rem_gtpu_bearer(uint16_t rnti, uint32_t pdu_session_id); + uint8_t allocate_lcid(uint32_t rnti); }; } // namespace srsenb -#endif // SRSENB_NGAP_UE_BEARER_MANAGER_H \ No newline at end of file +#endif // SRSENB_NGAP_UE_BEARER_MANAGER_H diff --git a/srsgnb/hdr/stack/rrc/rrc_nr.h b/srsgnb/hdr/stack/rrc/rrc_nr.h index bb8119f80..07c504dc2 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr.h @@ -46,6 +46,8 @@ namespace srsenb { +class enb_bearer_manager; + enum class rrc_nr_state_t { RRC_IDLE, RRC_INACTIVE, RRC_CONNECTED }; class rrc_nr final : public rrc_interface_pdcp_nr, @@ -64,7 +66,7 @@ public: rlc_interface_rrc* rlc, pdcp_interface_rrc* pdcp, ngap_interface_rrc_nr* ngap_, - gtpu_interface_rrc_nr* gtpu, + enb_bearer_manager& bearer_mapper_, rrc_eutra_interface_rrc_nr* rrc_eutra_); void stop(); @@ -82,6 +84,7 @@ public: void rem_user(uint16_t rnti); int update_user(uint16_t new_rnti, uint16_t old_rnti) final; void set_activity_user(uint16_t rnti) final; + int rrc_release(uint16_t rnti); // RLC interface // TODO @@ -109,6 +112,7 @@ public: srsran::const_byte_span nas_pdu, uint32_t lcid) final; int release_bearers(uint16_t rnti) final; + void release_user(uint16_t rnti) final; 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; @@ -129,13 +133,13 @@ private: rrc_nr_cfg_t cfg = {}; // interfaces - phy_interface_stack_nr* phy = nullptr; - mac_interface_rrc_nr* mac = nullptr; - rlc_interface_rrc* rlc = nullptr; - pdcp_interface_rrc* pdcp = nullptr; - gtpu_interface_rrc_nr* gtpu = nullptr; - ngap_interface_rrc_nr* ngap = nullptr; - rrc_eutra_interface_rrc_nr* rrc_eutra = nullptr; + phy_interface_stack_nr* phy = nullptr; + mac_interface_rrc_nr* mac = nullptr; + rlc_interface_rrc* rlc = nullptr; + pdcp_interface_rrc* pdcp = nullptr; + ngap_interface_rrc_nr* ngap = nullptr; + rrc_eutra_interface_rrc_nr* rrc_eutra = nullptr; + enb_bearer_manager* bearer_mapper = nullptr; // args srsran::task_sched_handle task_sched; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config.h b/srsgnb/hdr/stack/rrc/rrc_nr_config.h index 8ce9ff8c7..19e78aafc 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_config.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config.h @@ -60,6 +60,10 @@ struct rrc_nr_cfg_t { rrc_nr_cfg_sr_t sr_cfg; rrc_cfg_cqi_t cqi_cfg; rrc_cell_list_nr_t cell_list; + uint32_t inactivity_timeout_ms = 100000; + uint32_t enb_id; + uint16_t mcc; + uint16_t mnc; bool is_standalone; std::array nea_preference_list; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_ue.h b/srsgnb/hdr/stack/rrc/rrc_nr_ue.h index 232004729..f33c72379 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_ue.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_ue.h @@ -92,17 +92,17 @@ 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); - /* TS 38.331 - 5.3.3 RRC connection establishment */ + /** TS 38.331 - 5.3.3 RRC connection establishment */ 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); @@ -111,7 +111,7 @@ private: int update_rlc_bearers(const asn1::rrc_nr::cell_group_cfg_s& cell_group_diff); /// Update MAC based on ASN1 message - int update_mac(const asn1::rrc_nr::cell_group_cfg_s& cell_group_diff, bool is_config_complete); + int update_mac(const asn1::rrc_nr::cell_group_cfg_s& cell_group_config, bool is_config_complete); int pack_rrc_reconfiguration(asn1::dyn_octstring& packed_rrc_reconfig); int pack_secondary_cell_group_cfg(asn1::dyn_octstring& packed_secondary_cell_config); diff --git a/srsgnb/src/stack/gnb_stack_nr.cc b/srsgnb/src/stack/gnb_stack_nr.cc index 92c94feb4..f062e7098 100644 --- a/srsgnb/src/stack/gnb_stack_nr.cc +++ b/srsgnb/src/stack/gnb_stack_nr.cc @@ -21,9 +21,9 @@ #include "srsgnb/hdr/stack/gnb_stack_nr.h" #include "srsenb/hdr/stack/upper/gtpu.h" +#include "srsenb/hdr/stack/upper/gtpu_pdcp_adapter.h" #include "srsgnb/hdr/stack/ngap/ngap.h" #include "srsran/common/network_utils.h" -#include "srsran/common/standard_streams.h" #include "srsran/srsran.h" #include @@ -42,6 +42,7 @@ gnb_stack_nr::gnb_stack_nr(srslog::sink& log_sink) : mac(&task_sched), rrc(&task_sched), pdcp(&task_sched, pdcp_logger), + bearer_manager(new srsenb::enb_bearer_manager()), rlc(rlc_logger) { sync_task_queue = task_sched.make_task_queue(); @@ -77,6 +78,7 @@ int gnb_stack_nr::init(const gnb_stack_args_t& args_, stack_logger.set_level(srslog::str_to_basic_level(args.log.stack_level)); ngap_logger.set_level(srslog::str_to_basic_level(args.log.s1ap_level)); gtpu_logger.set_level(srslog::str_to_basic_level(args.log.gtpu_level)); + srslog::fetch_basic_logger("COMN", false).set_level(srslog::str_to_basic_level(args.log.stack_level)); mac_logger.set_hex_dump_max_size(args.log.mac_hex_limit); rlc_logger.set_hex_dump_max_size(args.log.rlc_hex_limit); @@ -85,11 +87,13 @@ int gnb_stack_nr::init(const gnb_stack_args_t& args_, stack_logger.set_hex_dump_max_size(args.log.stack_hex_limit); ngap_logger.set_hex_dump_max_size(args.log.s1ap_hex_limit); gtpu_logger.set_hex_dump_max_size(args.log.gtpu_hex_limit); + srslog::fetch_basic_logger("COMN", false).set_hex_dump_max_size(args.log.stack_hex_limit); if (x2_ == nullptr) { // SA mode ngap.reset(new srsenb::ngap(&task_sched, ngap_logger, &srsran::get_rx_io_manager())); gtpu.reset(new srsenb::gtpu(&task_sched, gtpu_logger, &srsran::get_rx_io_manager())); + gtpu_adapter.reset(new gtpu_pdcp_adapter(gtpu_logger, nullptr, &pdcp, gtpu.get(), *bearer_manager)); } // Init all layers @@ -99,25 +103,28 @@ int gnb_stack_nr::init(const gnb_stack_args_t& args_, } rlc.init(&pdcp, &rrc, &mac, task_sched.get_timer_handler()); - pdcp.init(&rlc, &rrc, x2_); - if (rrc.init(rrc_cfg_, phy, &mac, &rlc, &pdcp, ngap.get(), nullptr, x2_) != SRSRAN_SUCCESS) { + if (rrc.init(rrc_cfg_, phy, &mac, &rlc, &pdcp, ngap.get(), *bearer_manager, x2_) != SRSRAN_SUCCESS) { stack_logger.error("Couldn't initialize RRC"); return SRSRAN_ERROR; } if (ngap != nullptr) { + pdcp.init(&rlc, &rrc, gtpu_adapter.get()); + if (args.ngap_pcap.enable) { ngap_pcap.open(args.ngap_pcap.filename.c_str()); ngap->start_pcap(&ngap_pcap); } - ngap->init(args.ngap, &rrc, nullptr); + ngap->init(args.ngap, &rrc, gtpu.get()); gtpu_args_t gtpu_args; gtpu_args.embms_enable = false; gtpu_args.mme_addr = args.ngap.amf_addr; gtpu_args.gtp_bind_addr = args.ngap.gtp_bind_addr; - gtpu->init(gtpu_args, &pdcp); + gtpu->init(gtpu_args, gtpu_adapter.get()); + } else { + pdcp.init(&rlc, &rrc, x2_); } // TODO: add SDAP diff --git a/srsgnb/src/stack/mac/sched_nr_bwp.cc b/srsgnb/src/stack/mac/sched_nr_bwp.cc index a7fe2914c..a1585704b 100644 --- a/srsgnb/src/stack/mac/sched_nr_bwp.cc +++ b/srsgnb/src/stack/mac/sched_nr_bwp.cc @@ -33,8 +33,9 @@ ra_sched::ra_sched(const bwp_params_t& bwp_cfg_) : alloc_result ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_t& rar, uint32_t& nof_grants_alloc) { - const uint32_t rar_aggr_level = 2; - const prb_bitmap& prbs = slot_grid.res_grid()[slot_grid.get_pdcch_tti()].dl_prbs.prbs(); + const uint32_t rar_aggr_level = 2; + prb_bitmap prbs = slot_grid.res_grid()[slot_grid.get_pdcch_tti()].used_prbs(bwp_cfg->cfg.pdcch.ra_search_space.id, + srsran_dci_format_nr_1_0); alloc_result ret = alloc_result::other_cause; srsran::const_span msg3_grants{rar.msg3_grant}; diff --git a/srsgnb/src/stack/mac/sched_nr_cfg.cc b/srsgnb/src/stack/mac/sched_nr_cfg.cc index cdf35e882..48137534a 100644 --- a/srsgnb/src/stack/mac/sched_nr_cfg.cc +++ b/srsgnb/src/stack/mac/sched_nr_cfg.cc @@ -60,6 +60,7 @@ bwp_params_t::bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg P = get_P(cfg.rb_width, cfg.pdsch.rbg_size_cfg_1); N_rbg = get_nof_rbgs(cfg.rb_width, cfg.start_rb, cfg.pdsch.rbg_size_cfg_1); + cached_empty_prb_mask.resize(cfg.rb_width); // Derive params of individual slots uint32_t nof_slots = SRSRAN_NSLOTS_PER_FRAME_NR(cfg.numerology_idx); @@ -100,19 +101,30 @@ bwp_params_t::bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg } for (uint32_t ss_id = 0; ss_id < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ++ss_id) { - if (cell_cfg.bwps[0].pdcch.search_space_present[ss_id]) { - auto& ss = cell_cfg.bwps[0].pdcch.search_space[ss_id]; - auto& coreset = cell_cfg.bwps[0].pdcch.coreset[ss.coreset_id]; - common_cce_list.emplace(ss_id); - bwp_cce_pos_list& ss_cce_list = common_cce_list[ss_id]; - for (uint32_t sl = 0; sl < SRSRAN_NOF_SF_X_FRAME; ++sl) { - for (uint32_t agg_idx = 0; agg_idx < MAX_NOF_AGGR_LEVELS; ++agg_idx) { - ss_cce_list[sl][agg_idx].resize(SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR); - int n = srsran_pdcch_nr_locations_coreset( - &coreset, &ss, SRSRAN_SIRNTI, agg_idx, sl, ss_cce_list[sl][agg_idx].data()); - srsran_assert(n >= 0, "Failed to configure DCI locations of search space id=%d", ss_id); - ss_cce_list[sl][agg_idx].resize(n); - } + if (not cell_cfg.bwps[0].pdcch.search_space_present[ss_id]) { + continue; + } + auto& ss = cell_cfg.bwps[0].pdcch.search_space[ss_id]; + auto& coreset = cell_cfg.bwps[0].pdcch.coreset[ss.coreset_id]; + common_cce_list.emplace(ss_id); + bwp_cce_pos_list& ss_cce_list = common_cce_list[ss_id]; + for (uint32_t sl = 0; sl < SRSRAN_NOF_SF_X_FRAME; ++sl) { + for (uint32_t agg_idx = 0; agg_idx < MAX_NOF_AGGR_LEVELS; ++agg_idx) { + ss_cce_list[sl][agg_idx].resize(SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR); + int n = srsran_pdcch_nr_locations_coreset( + &coreset, &ss, SRSRAN_SIRNTI, agg_idx, sl, ss_cce_list[sl][agg_idx].data()); + srsran_assert(n >= 0, "Failed to configure DCI locations of search space id=%d", ss_id); + ss_cce_list[sl][agg_idx].resize(n); + } + } + + if (SRSRAN_SEARCH_SPACE_IS_COMMON(ss.type)) { + used_common_prb_masks.emplace(ss_id, cached_empty_prb_mask); + uint32_t coreset_start = srsran_coreset_start_rb(&cfg.pdcch.coreset[ss.coreset_id]); + used_common_prb_masks[ss_id].fill(0, coreset_start, true); + if (ss.coreset_id == 0) { + uint32_t coreset0_bw = srsran_coreset_get_bw(&cfg.pdcch.coreset[0]); + used_common_prb_masks[ss_id].fill(coreset_start + coreset0_bw, cfg.rb_width, true); } } } diff --git a/srsgnb/src/stack/mac/sched_nr_helpers.cc b/srsgnb/src/stack/mac/sched_nr_helpers.cc index dc03a8c14..a5182e12a 100644 --- a/srsgnb/src/stack/mac/sched_nr_helpers.cc +++ b/srsgnb/src/stack/mac/sched_nr_helpers.cc @@ -93,6 +93,7 @@ void fill_dci_grant(const bwp_params_t& bwp_cfg, const prb_grant& grant, srsran_ if (dci.ctx.coreset_id == 0 and SRSRAN_SEARCH_SPACE_IS_COMMON(dci.ctx.ss_type)) { nof_prb = dci.coreset0_bw; } + srsran_assert(grant.prbs().start() >= rb_start, "Invalid PRB index=%d < %d", grant.prbs().start(), rb_start); uint32_t grant_start = grant.prbs().start() - rb_start; dci.freq_domain_assigment = srsran_ra_nr_type1_riv(nof_prb, grant_start, grant.prbs().length()); } @@ -242,9 +243,9 @@ void log_sched_bwp_result(srslog::basic_logger& logger, data_count++; } else if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_ra) { const pdsch_t& pdsch = bwp_slot.dl.phy.pdsch[std::distance(bwp_slot.dl.phy.pdcch_dl.data(), &pdcch)]; - srsran::const_span prbs{pdsch.sch.grant.prb_idx, pdsch.sch.grant.prb_idx + pdsch.sch.grant.nof_prb}; + srsran::const_span prbs{pdsch.sch.grant.prb_idx, pdsch.sch.grant.prb_idx + SRSRAN_MAX_PRB_NR}; uint32_t start_idx = std::distance(prbs.begin(), std::find(prbs.begin(), prbs.end(), true)); - uint32_t end_idx = std::distance(prbs.begin(), std::find(prbs.begin() + start_idx, prbs.end(), false)); + uint32_t end_idx = start_idx + pdsch.sch.grant.nof_prb; fmt::format_to(fmtbuf, "SCHED: RAR, cc={}, ra-rnti=0x{:x}, prbs={}, pdsch_slot={}, msg3_slot={}, nof_grants={}", res_grid.cfg->cc, @@ -257,9 +258,9 @@ void log_sched_bwp_result(srslog::basic_logger& logger, } else if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_si) { if (logger.debug.enabled()) { const pdsch_t& pdsch = bwp_slot.dl.phy.pdsch[std::distance(bwp_slot.dl.phy.pdcch_dl.data(), &pdcch)]; - srsran::const_span prbs{pdsch.sch.grant.prb_idx, pdsch.sch.grant.prb_idx + pdsch.sch.grant.nof_prb}; + srsran::const_span prbs{pdsch.sch.grant.prb_idx, pdsch.sch.grant.prb_idx + SRSRAN_MAX_PRB_NR}; uint32_t start_idx = std::distance(prbs.begin(), std::find(prbs.begin(), prbs.end(), true)); - uint32_t end_idx = std::distance(prbs.begin(), std::find(prbs.begin() + start_idx, prbs.end(), false)); + uint32_t end_idx = start_idx + pdsch.sch.grant.nof_prb; fmt::format_to(fmtbuf, "SCHED: SI{}, cc={}, prbs={}, pdsch_slot={}", pdcch.dci.sii == 0 ? "B" : " message", diff --git a/srsgnb/src/stack/mac/sched_nr_ue.cc b/srsgnb/src/stack/mac/sched_nr_ue.cc index bae2fb470..8cd818f4c 100644 --- a/srsgnb/src/stack/mac/sched_nr_ue.cc +++ b/srsgnb/src/stack/mac/sched_nr_ue.cc @@ -170,16 +170,16 @@ void ue::mac_buffer_state(uint32_t ce_lcid, uint32_t nof_cmds) } } -void ue::rlc_buffer_state(uint32_t lcid, uint32_t newtx, uint32_t retx) +void ue::rlc_buffer_state(uint32_t lcid, uint32_t newtx, uint32_t priotx) { - if (lcid == 0 and buffers.get_dl_tx_total(0) == 0) { + if (lcid == 0 and (newtx + priotx > 0) and buffers.get_dl_tx_total(0) == 0) { // In case of DL-CCCH, schedule ConRes CE // Note1: rlc_buffer_state may be called multiple times for the same CCCH. Thus, we need to confirm lcid=0 buffer // state is zero to avoid that multiple CEs being scheduled. // Note2: use push_front because ConRes CE has priority buffers.pending_ces.push_front({srsran::mac_sch_subpdu_nr::CON_RES_ID, cfg().carriers[0].cc}); } - buffers.dl_buffer_state(lcid, newtx, retx); + buffers.dl_buffer_state(lcid, newtx, priotx); } void ue::new_slot(slot_point pdcch_slot) diff --git a/srsgnb/src/stack/ngap/ngap.cc b/srsgnb/src/stack/ngap/ngap.cc index a7c794942..a2d75b3a3 100644 --- a/srsgnb/src/stack/ngap/ngap.cc +++ b/srsgnb/src/stack/ngap/ngap.cc @@ -274,6 +274,23 @@ void ngap::write_pdu(uint16_t rnti, srsran::const_byte_span pdu) u->send_ul_nas_transport(pdu); } +void ngap::user_release_request(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) +{ + ue* u = users.find_ue_rnti(rnti); + if (u == nullptr) { + logger.warning("Released UE rnti=0x%x not found.", rnti); + return; + } + + cause_c cause; + cause.set_radio_network().value = cause_radio; + if (not u->send_ue_context_release_request(cause)) { + logger.error("Failed to initiate RRC Release for rnti=0x%x. Removing user", rnti); + rrc->release_user(rnti); + users.erase(u); + } +} + /********************************************************* * ngap::user_list class *********************************************************/ @@ -385,6 +402,7 @@ bool ngap::handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu) pcap->write_ngap(pdu->msg, pdu->N_bytes); } + // Unpack ngap_pdu_c rx_pdu; asn1::cbit_ref bref(pdu->msg, pdu->N_bytes); @@ -396,6 +414,10 @@ bool ngap::handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu) return false; } + // Logging + log_ngap_message(rx_pdu, Rx, srsran::make_span(*pdu)); + + // Handle the NGAP message switch (rx_pdu.type().value) { case ngap_pdu_c::types_opts::init_msg: return handle_initiating_message(rx_pdu.init_msg()); @@ -419,7 +441,7 @@ bool ngap::handle_initiating_message(const asn1::ngap_nr::init_msg_s& msg) case ngap_elem_procs_o::init_msg_c::types_opts::init_context_setup_request: return handle_initial_ctxt_setup_request(msg.value.init_context_setup_request()); case ngap_elem_procs_o::init_msg_c::types_opts::ue_context_release_cmd: - return handle_ue_ctxt_release_cmd(msg.value.ue_context_release_cmd()); + return handle_ue_context_release_cmd(msg.value.ue_context_release_cmd()); case ngap_elem_procs_o::init_msg_c::types_opts::pdu_session_res_setup_request: return handle_ue_pdu_session_res_setup_request(msg.value.pdu_session_res_setup_request()); default: @@ -534,7 +556,7 @@ bool ngap::handle_initial_ctxt_setup_request(const asn1::ngap_nr::init_context_s return true; } -bool ngap::handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg) +bool ngap::handle_ue_context_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg) { const asn1::ngap_nr::ue_ngap_id_pair_s& ue_ngap_id_pair = msg.protocol_ies.ue_ngap_ids.value.ue_ngap_id_pair(); @@ -544,9 +566,7 @@ bool ngap::handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cm return false; } - u->handle_ue_ctxt_release_cmd(msg); - - return true; + return u->handle_ue_context_release_cmd(msg); } bool ngap::handle_ue_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg) @@ -814,4 +834,30 @@ void ngap::start_pcap(srsran::ngap_pcap* pcap_) { pcap = pcap_; } + +void ngap::log_ngap_message(const ngap_pdu_c& msg, const direction_t dir, srsran::const_byte_span pdu) +{ + std::string msg_type = {}; + switch (msg.type().value) { + case ngap_pdu_c::types_opts::init_msg: + msg_type = msg.init_msg().value.type().to_string(); + break; + case ngap_pdu_c::types_opts::successful_outcome: + msg_type = msg.successful_outcome().value.type().to_string(); + break; + case ngap_pdu_c::types_opts::unsuccessful_outcome: + msg_type = msg.unsuccessful_outcome().value.type().to_string(); + break; + default: + return; + } + if (logger.debug.enabled()) { + asn1::json_writer json_writer; + msg.to_json(json_writer); + logger.debug(pdu.data(), pdu.size(), "%s - %s (%d B)", (dir == Rx) ? "Rx" : "Tx", msg_type, pdu.size()); + logger.debug("Content:%s", json_writer.to_string().c_str()); + } else if (logger.info.enabled()) { + logger.info(pdu.data(), pdu.size(), "%s - %s (%d B)", (dir == Rx) ? "Rx" : "Tx", msg_type, pdu.size()); + } +} } // namespace srsenb diff --git a/srsgnb/src/stack/ngap/ngap_ue.cc b/srsgnb/src/stack/ngap/ngap_ue.cc index 52e964d2c..a26b55696 100644 --- a/srsgnb/src/stack/ngap/ngap_ue.cc +++ b/srsgnb/src/stack/ngap/ngap_ue.cc @@ -253,6 +253,43 @@ bool ngap::ue::send_ue_ctxt_release_complete() return ngap_ptr->sctp_send_ngap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseComplete"); } +bool ngap::ue::send_ue_context_release_request(asn1::ngap_nr::cause_c cause) +{ + if (not ngap_ptr->amf_connected) { + logger.warning("AMF not connected"); + return false; + } + + if (was_ue_context_release_requested()) { + // let timeout auto-remove user. + return false; + } + release_requested = true; + + ngap_pdu_c tx_pdu; + tx_pdu.set_init_msg().load_info_obj(ASN1_NGAP_NR_ID_UE_CONTEXT_RELEASE_REQUEST); + ue_context_release_request_s& container = tx_pdu.init_msg().value.ue_context_release_request(); + + container.protocol_ies.cause.value = cause; + + // PDU Session Resource List + auto& session_lst = container.protocol_ies.pdu_session_res_list_cxt_rel_req.value; + for (const auto& pdu_pair : bearer_manager.pdu_sessions()) { + const ngap_ue_bearer_manager::pdu_session_t& session = pdu_pair.second; + + pdu_session_res_item_cxt_rel_req_s obj; + obj.pdu_session_id = session.id; + session_lst.push_back(obj); + } + container.protocol_ies.pdu_session_res_list_cxt_rel_req_present = session_lst.size() > 0; + + container.protocol_ies.ran_ue_ngap_id.value = ctxt.ran_ue_ngap_id; + container.protocol_ies.amf_ue_ngap_id.value = ctxt.amf_ue_ngap_id.value(); + + // TODO: Implement timeout + return ngap_ptr->sctp_send_ngap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseRequest"); +} + /******************************************************************************* /* NGAP message handler ********************************************************************************/ @@ -266,7 +303,7 @@ bool ngap::ue::handle_initial_ctxt_setup_request(const asn1::ngap_nr::init_conte return true; } -bool ngap::ue::handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg) +bool ngap::ue::handle_ue_context_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg) { // TODO: Release UE context if (not ue_context_release_proc.launch(msg)) { diff --git a/srsgnb/src/stack/ngap/ngap_ue_bearer_manager.cc b/srsgnb/src/stack/ngap/ngap_ue_bearer_manager.cc index 4d124ed9a..bc8a1bcd4 100644 --- a/srsgnb/src/stack/ngap/ngap_ue_bearer_manager.cc +++ b/srsgnb/src/stack/ngap/ngap_ue_bearer_manager.cc @@ -46,6 +46,8 @@ int ngap_ue_bearer_manager::add_pdu_session(uint16_t return SRSRAN_ERROR; } + lcid = allocate_lcid(rnti); + // TODO: remove lcid and just use pdu_session_id and rnti as id for GTP tunnel int rtn = add_gtpu_bearer(rnti, pdu_session_id, teid_out, addr_out, tunnel); if (rtn != SRSRAN_SUCCESS) { @@ -71,6 +73,7 @@ int ngap_ue_bearer_manager::reset_pdu_sessions(uint16_t rnti) auto pdu_session_id = iter->first; rem_gtpu_bearer(pdu_session_id, rnti); } + next_lcid_list.erase(rnti); return true; } @@ -119,4 +122,12 @@ void ngap_ue_bearer_manager::rem_gtpu_bearer(uint16_t rnti, uint32_t pdu_session gtpu->rem_bearer(rnti, it->second.lcid); } -} // namespace srsenb \ No newline at end of file +uint8_t ngap_ue_bearer_manager::allocate_lcid(uint32_t rnti) +{ + if (next_lcid_list.find(rnti) == next_lcid_list.end()) { + next_lcid_list[rnti] = 4; + } + return next_lcid_list[rnti]++; +} + +} // namespace srsenb diff --git a/srsgnb/src/stack/ngap/ngap_ue_proc.cc b/srsgnb/src/stack/ngap/ngap_ue_proc.cc index 473748d1a..fdf44c0e8 100644 --- a/srsgnb/src/stack/ngap/ngap_ue_proc.cc +++ b/srsgnb/src/stack/ngap/ngap_ue_proc.cc @@ -90,9 +90,8 @@ ngap_ue_ue_context_release_proc::ngap_ue_ue_context_release_proc(ngap_interface_ proc_outcome_t ngap_ue_ue_context_release_proc::init(const asn1::ngap_nr::ue_context_release_cmd_s& msg) { logger.info("Started %s", name()); - // TODO: How to approach erasing users ? bearer_manager->reset_pdu_sessions(ue_ctxt->rnti); - rrc->release_bearers(ue_ctxt->rnti); + rrc->release_user(ue_ctxt->rnti); parent->send_ue_ctxt_release_complete(); return proc_outcome_t::success; } @@ -152,8 +151,8 @@ proc_outcome_t ngap_ue_pdu_session_res_setup_proc::init(const asn1::ngap_nr::pdu // TODO: Check cause asn1::ngap_nr::cause_c cause; - uint32_t teid_in; - uint16_t lcid; + uint32_t teid_in = {}; + uint16_t lcid = {}; asn1::bounded_bitstring<1, 160, true, true> addr_in; if (bearer_manager->add_pdu_session( diff --git a/srsgnb/src/stack/ngap/test/ngap_test.cc b/srsgnb/src/stack/ngap/test/ngap_test.cc index 584370f7a..8e2eca599 100644 --- a/srsgnb/src/stack/ngap/test/ngap_test.cc +++ b/srsgnb/src/stack/ngap/test/ngap_test.cc @@ -124,6 +124,7 @@ public: } int release_bearers(uint16_t rnti) { return SRSRAN_SUCCESS; } + void release_user(uint16_t rnti) {} int allocate_lcid(uint16_t rnti) { return SRSRAN_SUCCESS; } void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) {} diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index dbfa72136..14203d7cc 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -20,6 +20,7 @@ */ #include "srsgnb/hdr/stack/rrc/cell_asn1_config.h" +#include "srsenb/hdr/common/common_enb.h" #include "srsran/asn1/obj_id_cmp_utils.h" #include "srsran/asn1/rrc_nr_utils.h" #include "srsran/common/band_helper.h" @@ -478,9 +479,9 @@ void fill_pucch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pucch_cfg sr_res1.sched_request_res_id = 1; sr_res1.sched_request_id = 0; sr_res1.periodicity_and_offset_present = true; - sr_res1.periodicity_and_offset.set_sl40() = 0; + sr_res1.periodicity_and_offset.set_sl40() = 8; sr_res1.res_present = true; - sr_res1.res = 16; + sr_res1.res = 2; // DL data out.dl_data_to_ul_ack_present = true; @@ -883,6 +884,7 @@ int fill_master_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1 phr.phr_type2_other_cell = false; phr.phr_mode_other_cg.value = asn1::rrc_nr::phr_cfg_s::phr_mode_other_cg_opts::real; out.mac_cell_group_cfg.skip_ul_tx_dynamic = false; + out.mac_cell_group_cfg.phr_cfg_present = false; // Note: not supported // physicalCellGroupConfig -- Need M out.phys_cell_group_cfg_present = true; @@ -895,7 +897,7 @@ int fill_master_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1 out.sp_cell_cfg_present = true; fill_sp_cell_cfg_from_enb_cfg(cfg, cc, out.sp_cell_cfg); out.sp_cell_cfg.recfg_with_sync_present = false; - out.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present = false; + out.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present = false; // Note: not supported return SRSRAN_SUCCESS; } @@ -1067,8 +1069,6 @@ void fill_serv_cell_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, serving_ce int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::sib1_s& sib1) { - std::string plmn_str = "00101"; - uint32_t cell_id = 0x19B01; const rrc_cell_cfg_nr_t& cell_cfg = cfg.cell_list[cc]; sib1.cell_sel_info_present = true; @@ -1079,11 +1079,11 @@ int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::s sib1.cell_access_related_info.plmn_id_list.resize(1); sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list.resize(1); srsran::plmn_id_t plmn; - plmn.from_string(plmn_str); + plmn.from_number(cfg.mcc, cfg.mnc); srsran::to_asn1(&sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list[0], plmn); sib1.cell_access_related_info.plmn_id_list[0].tac_present = true; sib1.cell_access_related_info.plmn_id_list[0].tac.from_number(cell_cfg.tac); - sib1.cell_access_related_info.plmn_id_list[0].cell_id.from_number(cell_id); + sib1.cell_access_related_info.plmn_id_list[0].cell_id.from_number((cfg.enb_id << 8U) + cell_cfg.phy_cell.cell_id); sib1.cell_access_related_info.plmn_id_list[0].cell_reserved_for_oper.value = plmn_id_info_s::cell_reserved_for_oper_opts::not_reserved; @@ -1162,7 +1162,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.drb_id + (int)srsran::nr_srb::count - 1; + 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 74d919406..d4d1fa435 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -26,6 +26,7 @@ #include "srsgnb/hdr/stack/rrc/rrc_nr_ue.h" #include "srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h" #include "srsran/asn1/rrc_nr_utils.h" +#include "srsran/common/bearer_manager.h" #include "srsran/common/common_nr.h" #include "srsran/common/phy_cfg_nr_default.h" #include "srsran/common/standard_streams.h" @@ -47,16 +48,16 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, rlc_interface_rrc* rlc_, pdcp_interface_rrc* pdcp_, ngap_interface_rrc_nr* ngap_, - gtpu_interface_rrc_nr* gtpu_, + enb_bearer_manager& bearer_mapper_, rrc_eutra_interface_rrc_nr* rrc_eutra_) { - phy = phy_; - mac = mac_; - rlc = rlc_; - pdcp = pdcp_; - ngap = ngap_; - gtpu = gtpu_; - rrc_eutra = rrc_eutra_; + phy = phy_; + mac = mac_; + rlc = rlc_; + pdcp = pdcp_; + ngap = ngap_; + bearer_mapper = &bearer_mapper_; + rrc_eutra = rrc_eutra_; cfg = cfg_; @@ -212,6 +213,13 @@ void rrc_nr::rem_user(uint16_t rnti) } } +/// This function is called when the INACTIVITY TIMER FOR +int rrc_nr::rrc_release(uint16_t rnti) +{ + // TODO: we do not have yet a defined procedure to handle this + return SRSRAN_SUCCESS; +} + /* Function called by MAC after the reception of a C-RNTI CE indicating that the UE still has a * valid RNTI. */ @@ -252,10 +260,11 @@ void rrc_nr::set_activity_user(uint16_t rnti) } ue* ue_ptr = it->second.get(); + // Restart inactivity timer for RRC-NR + ue_ptr->set_activity(); + // inform EUTRA RRC about user activity if (ue_ptr->is_endc()) { - // Restart inactivity timer for RRC-NR - ue_ptr->set_activity(); // inform EUTRA RRC about user activity rrc_eutra->set_activity_user(ue_ptr->get_eutra_rnti()); } @@ -618,6 +627,9 @@ int rrc_nr::establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran: } users[rnti]->establish_eps_bearer(pdu_session_id, nas_pdu, lcid); + + // TODO: verify whether this is the best place where to call the RRCReconfig + users[rnti]->send_rrc_reconfiguration(); return SRSRAN_SUCCESS; } @@ -626,6 +638,16 @@ int rrc_nr::release_bearers(uint16_t rnti) return SRSRAN_SUCCESS; } +void rrc_nr::release_user(uint16_t rnti) +{ + if (not users.contains(rnti)) { + logger.warning("User rnti=0x%x has already been released", rnti); + return; + } + + users[rnti]->send_rrc_release(); +} + int rrc_nr::allocate_lcid(uint16_t rnti) { return SRSRAN_SUCCESS; diff --git a/srsgnb/src/stack/rrc/rrc_nr_ue.cc b/srsgnb/src/stack/rrc/rrc_nr_ue.cc index aca98b202..bd9dea098 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_ue.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_ue.cc @@ -23,6 +23,7 @@ #include "srsgnb/hdr/stack/rrc/cell_asn1_config.h" #include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h" #include "srsran/asn1/rrc_nr_utils.h" +#include "srsran/common/bearer_manager.h" #include "srsran/common/string_helpers.h" using namespace asn1::rrc_nr; @@ -67,8 +68,7 @@ void rrc_nr::ue::set_activity_timeout(activity_timeout_type_t type) deadline_ms = 5000; break; case UE_INACTIVITY_TIMEOUT: - // TODO: Retrieve the parameters from somewhere(RRC?) - Currently hardcoded to 5s - deadline_ms = 10000; + deadline_ms = parent->cfg.inactivity_timeout_ms; break; default: logger.error("Unknown timeout type %d", type); @@ -102,10 +102,16 @@ void rrc_nr::ue::activity_timer_expired(const activity_timeout_type_t type) switch (type) { case MSG5_RX_TIMEOUT: - case UE_INACTIVITY_TIMEOUT: + case UE_INACTIVITY_TIMEOUT: { state = rrc_nr_state_t::RRC_INACTIVE; - parent->rrc_eutra->sgnb_inactivity_timeout(eutra_rnti); + if (parent->cfg.is_standalone) { + // Start NGAP Release UE context + parent->ngap->user_release_request(rnti, asn1::ngap_nr::cause_radio_network_opts::user_inactivity); + } else { + parent->rrc_eutra->sgnb_inactivity_timeout(eutra_rnti); + } break; + } case MSG3_RX_TIMEOUT: { // MSG3 timeout, no need to notify NGAP or LTE stack. Just remove UE state = rrc_nr_state_t::RRC_IDLE; @@ -1020,7 +1026,7 @@ void rrc_nr::ue::send_security_mode_command(srsran::unique_byte_buffer_t nas_pdu ies.security_cfg_smc.security_algorithm_cfg = sec_ctx.get_security_algorithm_cfg(); if (send_dl_dcch(srsran::nr_srb::srb1, dl_dcch_msg) != SRSRAN_SUCCESS) { - send_rrc_release(); + parent->ngap->user_release_request(rnti, asn1::ngap_nr::cause_radio_network_opts::radio_res_not_available); } } @@ -1030,6 +1036,7 @@ void rrc_nr::ue::handle_security_mode_complete(const asn1::rrc_nr::security_mode parent->logger.info("SecurityModeComplete transaction ID: %d", msg.rrc_transaction_id); parent->pdcp->enable_encryption(rnti, srb_to_lcid(srsran::nr_srb::srb1)); + send_rrc_reconfiguration(); // Note: Skip UE capabilities // Send RRCReconfiguration if necessary @@ -1049,52 +1056,64 @@ void rrc_nr::ue::send_rrc_reconfiguration() ies.radio_bearer_cfg_present = compute_diff_radio_bearer_cfg(parent->cfg, radio_bearer_cfg, next_radio_bearer_cfg, ies.radio_bearer_cfg); - ies.non_crit_ext_present = true; - ies.non_crit_ext.master_cell_group_present = true; + // If no bearer to add/mod/remove, do not include master_cell_group + // Set ies.non_crit_ext_present (a few lines below) only if + // master_cell_group_present == true or ies.non_crit_ext.ded_nas_msg_list_present == true + if (ies.radio_bearer_cfg_present) { + ies.non_crit_ext.master_cell_group_present = true; - // Fill masterCellGroup - cell_group_cfg_s master_cell_group; - master_cell_group.cell_group_id = 0; - fill_cellgroup_with_radio_bearer_cfg(parent->cfg, ies.radio_bearer_cfg, master_cell_group); + // Fill masterCellGroup + cell_group_cfg_s master_cell_group; + master_cell_group.cell_group_id = 0; + fill_cellgroup_with_radio_bearer_cfg(parent->cfg, ies.radio_bearer_cfg, master_cell_group); - // Pack masterCellGroup into container - srsran::unique_byte_buffer_t pdu = parent->pack_into_pdu(master_cell_group, __FUNCTION__); - if (pdu == nullptr) { - send_rrc_release(); - return; - } - 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); - - // Pass stored NAS PDUs - ies.non_crit_ext.ded_nas_msg_list_present = true; - ies.non_crit_ext.ded_nas_msg_list.resize(nas_pdu_queue.size()); - for (uint32_t i = 0; i < nas_pdu_queue.size(); ++i) { - ies.non_crit_ext.ded_nas_msg_list[i].resize(nas_pdu_queue[i]->size()); - memcpy(ies.non_crit_ext.ded_nas_msg_list[i].data(), nas_pdu_queue[i]->data(), nas_pdu_queue[i]->size()); - } - ies.non_crit_ext.ded_nas_msg_list_present = nas_pdu_queue.size() > 0; - nas_pdu_queue.clear(); + // Pack masterCellGroup into container + srsran::unique_byte_buffer_t pdu = parent->pack_into_pdu(master_cell_group, __FUNCTION__); + if (pdu == nullptr) { + parent->ngap->user_release_request(rnti, asn1::ngap_nr::cause_radio_network_opts::radio_res_not_available); + return; + } + 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()); + } - // Update lower layers - if (ies.radio_bearer_cfg_present) { - // add PDCP bearers - update_pdcp_bearers(ies.radio_bearer_cfg, master_cell_group); + // Update lower layers + // add MAC bearers + update_mac(master_cell_group, false); // add RLC bearers update_rlc_bearers(master_cell_group); - // add MAC bearers - update_mac(master_cell_group, false); + // add PDCP bearers + update_pdcp_bearers(ies.radio_bearer_cfg, master_cell_group); } + if (nas_pdu_queue.size() > 0) { + // Pass stored NAS PDUs + ies.non_crit_ext.ded_nas_msg_list_present = true; + ies.non_crit_ext.ded_nas_msg_list.resize(nas_pdu_queue.size()); + for (uint32_t i = 0; i < nas_pdu_queue.size(); ++i) { + ies.non_crit_ext.ded_nas_msg_list[i].resize(nas_pdu_queue[i]->size()); + memcpy(ies.non_crit_ext.ded_nas_msg_list[i].data(), nas_pdu_queue[i]->data(), nas_pdu_queue[i]->size()); + } + nas_pdu_queue.clear(); + } + + ies.non_crit_ext_present = ies.non_crit_ext.master_cell_group_present or ies.non_crit_ext.ded_nas_msg_list_present; + if (send_dl_dcch(srsran::nr_srb::srb1, dl_dcch_msg) != SRSRAN_SUCCESS) { - send_rrc_release(); + parent->ngap->user_release_request(rnti, asn1::ngap_nr::cause_radio_network_opts::radio_res_not_available); } } 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); @@ -1102,7 +1121,21 @@ void rrc_nr::ue::handle_rrc_reconfiguration_complete(const asn1::rrc_nr::rrc_rec void rrc_nr::ue::send_rrc_release() { - // TODO + static const uint32_t release_delay = 60; // Taken from TS 38.331, 5.3.8.3 + + dl_dcch_msg_s dl_dcch_msg; + rrc_release_s& release = dl_dcch_msg.msg.set_c1().set_rrc_release(); + + release.rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + rrc_release_ies_s& ies = release.crit_exts.set_rrc_release(); + + ies.suspend_cfg_present = false; // goes to RRC_IDLE + + send_dl_dcch(srsran::nr_srb::srb1, dl_dcch_msg); + state = rrc_nr_state_t::RRC_IDLE; + + // TODO: Obtain acknowledgment from lower layers that RRC Release was received + parent->task_sched.defer_callback(release_delay, [this]() { parent->rem_user(rnti); }); } void rrc_nr::ue::send_dl_information_transfer(srsran::unique_byte_buffer_t sdu) @@ -1116,7 +1149,7 @@ void rrc_nr::ue::send_dl_information_transfer(srsran::unique_byte_buffer_t sdu) memcpy(ies.ded_nas_msg.data(), sdu->data(), ies.ded_nas_msg.size()); if (send_dl_dcch(srsran::nr_srb::srb1, dl_dcch_msg) != SRSRAN_SUCCESS) { - send_rrc_release(); + parent->ngap->user_release_request(rnti, asn1::ngap_nr::cause_radio_network_opts::radio_res_not_available); } } @@ -1157,6 +1190,7 @@ void rrc_nr::ue::establish_eps_bearer(uint32_t pdu_session_id, srsran::const_byt drb.drb_id = 1; drb.pdcp_cfg_present = true; + drb.pdcp_cfg.drb_present = true; drb.pdcp_cfg.drb.discard_timer_present = true; drb.pdcp_cfg.drb.discard_timer.value = pdcp_cfg_s::drb_s_::discard_timer_opts::ms100; drb.pdcp_cfg.drb.pdcp_sn_size_ul_present = true; @@ -1169,6 +1203,11 @@ void rrc_nr::ue::establish_eps_bearer(uint32_t pdu_session_id, srsran::const_byt next_radio_bearer_cfg.drb_to_add_mod_list_present = true; next_radio_bearer_cfg.drb_to_add_mod_list.push_back(drb); + + parent->bearer_mapper->add_eps_bearer( + rnti, lcid - 3, srsran::srsran_rat_t::nr, lcid); // TODO: configurable bearer id <-> lcid mapping + + logger.info("Established EPS bearer for LCID %u and RNTI 0x%x", lcid, rnti); } bool rrc_nr::ue::init_pucch() @@ -1247,15 +1286,15 @@ int rrc_nr::ue::update_rlc_bearers(const asn1::rrc_nr::cell_group_cfg_s& cell_gr return SRSRAN_SUCCESS; } -int rrc_nr::ue::update_mac(const cell_group_cfg_s& cell_group_diff, bool is_config_complete) +int rrc_nr::ue::update_mac(const cell_group_cfg_s& cell_group_config, bool is_config_complete) { if (not is_config_complete) { // Release bearers - for (uint8_t lcid : cell_group_diff.rlc_bearer_to_release_list) { + for (uint8_t lcid : cell_group_config.rlc_bearer_to_release_list) { uecfg.ue_bearers[lcid].direction = mac_lc_ch_cfg_t::IDLE; } - for (const rlc_bearer_cfg_s& bearer : cell_group_diff.rlc_bearer_to_add_mod_list) { + for (const rlc_bearer_cfg_s& bearer : cell_group_config.rlc_bearer_to_add_mod_list) { uecfg.ue_bearers[bearer.lc_ch_id].direction = mac_lc_ch_cfg_t::BOTH; if (bearer.mac_lc_ch_cfg.ul_specific_params_present) { uecfg.ue_bearers[bearer.lc_ch_id].priority = bearer.mac_lc_ch_cfg.ul_specific_params.prio; @@ -1267,7 +1306,7 @@ int rrc_nr::ue::update_mac(const cell_group_cfg_s& cell_group_diff, bool is_conf } } } else { - auto& pdcch = cell_group_diff.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(); + auto& pdcch = cell_group_config.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(); for (auto& ss : pdcch.search_spaces_to_add_mod_list) { uecfg.phy_cfg.pdcch.search_space_present[ss.search_space_id] = true; uecfg.phy_cfg.pdcch.search_space[ss.search_space_id] = diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc index 4da6e6943..acc7703db 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc @@ -22,6 +22,7 @@ #include "rrc_nr_test_helpers.h" #include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h" #include "srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h" +#include "srsran/common/bearer_manager.h" #include "srsran/common/test_common.h" #include "srsran/interfaces/gnb_rrc_nr_interfaces.h" #include @@ -54,6 +55,7 @@ void test_sib_generation() rlc_dummy rlc_obj; pdcp_dummy pdcp_obj; rrc_nr rrc_obj(&task_sched); + enb_bearer_manager bearer_mapper; // set cfg rrc_nr_cfg_t rrc_cfg_nr = {}; @@ -65,10 +67,13 @@ void test_sib_generation() rrc_cfg_nr.cell_list[0].phy_cell.carrier.nof_prb = 52; rrc_cfg_nr.cell_list[0].duplex_mode = SRSRAN_DUPLEX_MODE_FDD; rrc_cfg_nr.is_standalone = true; + rrc_cfg_nr.enb_id = 0x19B; + srsran::string_to_mcc("001", &rrc_cfg_nr.mcc); + srsran::string_to_mnc("01", &rrc_cfg_nr.mnc); set_derived_nr_cell_params(rrc_cfg_nr.is_standalone, rrc_cfg_nr.cell_list[0]); srsran_assert(check_rrc_nr_cfg_valid(rrc_cfg_nr) == SRSRAN_SUCCESS, "Invalid RRC NR configuration"); - TESTASSERT(rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, nullptr, nullptr, nullptr) == + TESTASSERT(rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, nullptr, bearer_mapper, nullptr) == SRSRAN_SUCCESS); const sched_nr_interface::cell_cfg_t& nrcell = mac_obj.nr_cells.at(0); @@ -106,6 +111,7 @@ int test_rrc_setup() mac_nr_dummy mac_obj; rlc_dummy rlc_obj; pdcp_dummy pdcp_obj; + enb_bearer_manager bearer_mapper; rrc_nr rrc_obj(&task_sched); // set cfg @@ -117,9 +123,12 @@ int test_rrc_setup() rrc_cfg_nr.cell_list[0].band = 78; rrc_cfg_nr.cell_list[0].phy_cell.carrier.nof_prb = 52; rrc_cfg_nr.is_standalone = false; + rrc_cfg_nr.enb_id = 0x19B; + srsran::string_to_mcc("001", &rrc_cfg_nr.mcc); + srsran::string_to_mnc("01", &rrc_cfg_nr.mnc); set_derived_nr_cell_params(rrc_cfg_nr.is_standalone, rrc_cfg_nr.cell_list[0]); srsran_assert(check_rrc_nr_cfg_valid(rrc_cfg_nr) == SRSRAN_SUCCESS, "Invalid RRC NR configuration"); - TESTASSERT(rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, nullptr, nullptr, nullptr) == + TESTASSERT(rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, nullptr, bearer_mapper, nullptr) == SRSRAN_SUCCESS); for (uint32_t n = 0; n < 2; ++n) { @@ -142,7 +151,8 @@ void test_rrc_sa_connection() mac_nr_dummy mac_obj; rlc_nr_rrc_tester rlc_obj; pdcp_nr_rrc_tester pdcp_obj; - ngap_dummy ngap_obj; + ngap_rrc_tester ngap_obj; + enb_bearer_manager bearer_mapper; rrc_nr rrc_obj(&task_sched); @@ -156,10 +166,13 @@ void test_rrc_sa_connection() rrc_cfg_nr.cell_list[0].phy_cell.carrier.nof_prb = 52; rrc_cfg_nr.cell_list[0].duplex_mode = SRSRAN_DUPLEX_MODE_FDD; rrc_cfg_nr.is_standalone = true; + rrc_cfg_nr.enb_id = 0x19B; + srsran::string_to_mcc("001", &rrc_cfg_nr.mcc); + srsran::string_to_mnc("01", &rrc_cfg_nr.mnc); set_derived_nr_cell_params(rrc_cfg_nr.is_standalone, rrc_cfg_nr.cell_list[0]); srsran_assert(check_rrc_nr_cfg_valid(rrc_cfg_nr) == SRSRAN_SUCCESS, "Invalid RRC NR configuration"); - TESTASSERT(rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, &ngap_obj, nullptr, nullptr) == + TESTASSERT(rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, &ngap_obj, bearer_mapper, nullptr) == SRSRAN_SUCCESS); sched_nr_ue_cfg_t uecfg = get_default_ue_cfg(1); @@ -167,24 +180,41 @@ void test_rrc_sa_connection() uecfg.phy_cfg.pdcch.search_space_present[2] = false; TESTASSERT_SUCCESS(rrc_obj.add_user(0x4601, uecfg)); - test_rrc_nr_connection_establishment(task_sched, rrc_obj, rlc_obj, mac_obj, 0x4601); + 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, ngap_obj, 0x4601); + test_rrc_nr_2nd_reconfiguration(task_sched, rrc_obj, pdcp_obj, ngap_obj, 0x4601); } } // namespace srsenb int main(int argc, char** argv) { - auto& logger = srslog::fetch_basic_logger("ASN1"); + // Setup the log spy to intercept error and warning log entries. + if (!srslog::install_custom_sink( + srsran::log_sink_spy::name(), + std::unique_ptr(new srsran::log_sink_spy(srslog::get_default_log_formatter())))) { + return SRSRAN_ERROR; + } + + auto* spy = static_cast(srslog::find_sink(srsran::log_sink_spy::name())); + if (!spy) { + return SRSRAN_ERROR; + } + + auto& logger = srslog::fetch_basic_logger("ASN1", *spy, true); logger.set_level(srslog::basic_levels::info); - auto& rrc_logger = srslog::fetch_basic_logger("RRC-NR"); - rrc_logger.set_level(srslog::basic_levels::debug); + auto& test_log = srslog::fetch_basic_logger("RRC-NR", *spy, true); + test_log.set_level(srslog::basic_levels::debug); srslog::init(); srsenb::test_sib_generation(); TESTASSERT(srsenb::test_rrc_setup() == SRSRAN_SUCCESS); srsenb::test_rrc_sa_connection(); + TESTASSERT_EQ(0, spy->get_warning_counter()); + TESTASSERT_EQ(0, spy->get_error_counter()); return SRSRAN_SUCCESS; } 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 79fa21698..052854beb 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc @@ -21,6 +21,9 @@ #include "rrc_nr_test_helpers.h" #include "srsran/common/test_common.h" +#include + +#define NAS_SEC_CMD_STR "d9119b97d7bb59fc842d5b9cc12f00c27e9d5e4c80ee4cceb99a0dbbc6e0b54daa21a5d9e36d2e3b" using namespace asn1::rrc_nr; @@ -30,6 +33,7 @@ void test_rrc_nr_connection_establishment(srsran::task_scheduler& task_sched, rrc_nr& rrc_obj, rlc_nr_rrc_tester& rlc, mac_nr_dummy& mac, + ngap_rrc_tester& ngap, uint16_t rnti) { srsran::unique_byte_buffer_t pdu; @@ -105,8 +109,9 @@ void test_rrc_nr_connection_establishment(srsran::task_scheduler& task_sched, complete_ies.registered_amf.amf_id.from_number(0x800101); complete_ies.guami_type_present = true; complete_ies.guami_type.value = rrc_setup_complete_ies_s::guami_type_opts::native; - complete_ies.ded_nas_msg.from_string("7E01280E534C337E004109000BF200F110800101347B80802E02F07071002D7E004109000BF200F" - "110800101347B80801001002E02F0702F0201015200F11000006418010174000090530101"); + std::string NAS_msg_str = "7E01280E534C337E004109000BF200F110800101347B80802E02F07071002D7E004109000BF200F11080010134" + "7B80801001002E02F0702F0201015200F11000006418010174000090530101"; + auto& ded_nas_msg = complete_ies.ded_nas_msg.from_string(NAS_msg_str); { pdu = srsran::make_byte_buffer(); @@ -127,6 +132,77 @@ 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 unbounded_octstring for the expected MSG + asn1::unbounded_octstring expected; + expected.from_string(NAS_msg_str); + TESTASSERT(expected == ngap.last_pdu); +} + +void test_rrc_nr_info_transfer(srsran::task_scheduler& task_sched, + rrc_nr& rrc_obj, + pdcp_nr_rrc_tester& pdcp, + ngap_rrc_tester& ngap, + uint16_t rnti) +{ + // STEP 1 : Send DLInformationTransfer (gNB -> UE) + // generate sdu to pass as NAS message in DLInformationTransfer + srsran::unique_byte_buffer_t nsa_sdu; + nsa_sdu = srsran::make_byte_buffer(); + + // create an unbounded_octstring object that contains a random NAS message (we simulate a NAS message) + asn1::unbounded_octstring NAS_DL_msg; + NAS_DL_msg.from_string("21d9dfe07800371095c79a751be8352fb44aba7d69b836f5aad594ede9e72b8e34105ca8d7669d5c"); + nsa_sdu->append_bytes(NAS_DL_msg.data(), NAS_DL_msg.size()); + + // trigger the RRC to send the DLInformationTransfer + rrc_obj.write_dl_info(rnti, std::move(nsa_sdu)); + + // 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), pdcp.last_sdu_lcid); + + // Send SecurityModeCommand (gNB -> UE) + 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 if the unpacked message retrived from PCDP 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::dl_info_transfer, dl_dcch_msg.msg.c1().type().value); + TESTASSERT_EQ(dl_info_transfer_s::crit_exts_c_::types_opts::dl_info_transfer, + dl_dcch_msg.msg.c1().dl_info_transfer().crit_exts.type().value); + + dl_info_transfer_ies_s& ies_DL = dl_dcch_msg.msg.c1().dl_info_transfer().crit_exts.dl_info_transfer(); + TESTASSERT(ies_DL.ded_nas_msg_present == true); + TESTASSERT(NAS_DL_msg == ies_DL.ded_nas_msg); + + // STEP 2: Send ULInformationTransfer (UE -> gNB) + ul_dcch_msg_s ul_dcch_msg; + 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) + // We reuse ies_UL below to compare the string with the message sent to and unpacked by the gNB + ies_UL.ded_nas_msg.from_string("6671f8bc80b1860f29b3a8b3b8563ce6c36a591bb1a3dc6612674448fb958d274426d326356aa9aa"); + + 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)); + + // compare if the actual transmitted matches with the MSG created from the original string + TESTASSERT(ies_UL.ded_nas_msg == ngap.last_pdu); } void test_rrc_nr_security_mode_cmd(srsran::task_scheduler& task_sched, @@ -134,17 +210,22 @@ void test_rrc_nr_security_mode_cmd(srsran::task_scheduler& task_sched, pdcp_nr_rrc_tester& pdcp, uint16_t rnti) { - srsran::unique_byte_buffer_t pdu; + // 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(NAS_SEC_CMD_STR); + srsran::unique_byte_buffer_t nas_pdu; + nas_pdu = srsran::make_byte_buffer(); + nas_pdu->append_bytes(NAS_msg.data(), NAS_msg.size()); // Trigger Send SecurityCommand (simulate request from NGAP) - rrc_obj.start_security_mode_procedure(rnti, nullptr); + rrc_obj.start_security_mode_procedure(rnti, std::move(nas_pdu)); // 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()}; @@ -161,12 +242,13 @@ 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; auto& ies_complete = sec_cmd_complete_msg.crit_exts.set_security_mode_complete(); + srsran::unique_byte_buffer_t pdu; { pdu = srsran::make_byte_buffer(); asn1::bit_ref bref{pdu->data(), pdu->get_tailroom()}; @@ -178,4 +260,141 @@ 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, + ngap_rrc_tester& ngap, + uint16_t 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(); + + // create an unbounded_octstring object that contains the same NAS message as in SecurityModeCommand + // The RRCreconfiguration reads the SecurityModeCommand NAS msg previously saved in the queue + asn1::unbounded_octstring NAS_msg; + NAS_msg.from_string(NAS_SEC_CMD_STR); + TESTASSERT_EQ(true, reconf_ies.non_crit_ext.ded_nas_msg_list_present); + // Test if NAS_msg is the same as the one sent in SecurityModeCommand + TESTASSERT(NAS_msg == 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)); + + // Verify the NGAP gets notified for the RRCReconfigurationComplete + TESTASSERT_EQ(true, ngap.last_rrc_recnf_complete); +} + +void test_rrc_nr_2nd_reconfiguration(srsran::task_scheduler& task_sched, + rrc_nr& rrc_obj, + pdcp_nr_rrc_tester& pdcp, + ngap_rrc_tester& ngap, + uint16_t rnti) +{ + // Make sure the NGAP RRCReconfigurationComplete bool is reset to false + ngap.last_rrc_recnf_complete = false; + + // create an unbounded_octstring object that contains a NAS message (we simulate a random NAS nas) + asn1::unbounded_octstring NAS_msg; + NAS_msg.from_string("c574defc80ba722bffb8eacb6f8a163e3222cf1542ac529f6980bb15e0bf12d9f2b29f11fb458ec9"); + + // STEP 2 - Trigger and send RRCReconfiguration command (gNB -> UE) + rrc_obj.establish_rrc_bearer(rnti, 1, NAS_msg, srsran::srb_to_lcid(srsran::nr_srb::srb1)); + + // 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[0].drb_id, rlc_drb.served_radio_bearer.drb_id()); + + // Test if NAS_msg is the same as the one sent in DLInformationTransfer + TESTASSERT_EQ(true, reconf_ies.non_crit_ext.ded_nas_msg_list_present); + TESTASSERT(NAS_msg == 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)); + + // Verify the NGAP gets notified for the RRCReconfigurationComplete + TESTASSERT_EQ(true, ngap.last_rrc_recnf_complete); +} + } // 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 a871e77d8..0ce9e47af 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.h +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.h @@ -58,6 +58,34 @@ public: srsran::unique_byte_buffer_t last_sdu; }; +class ngap_rrc_tester : public ngap_dummy +{ +public: + void initial_ue(uint16_t rnti, + uint32_t gnb_cc_idx, + asn1::ngap_nr::rrcestablishment_cause_e cause, + srsran::const_byte_span pdu, + uint32_t s_tmsi) + { + last_sdu_rnti = rnti; + last_pdu.resize(pdu.size()); + memcpy(last_pdu.data(), pdu.data(), pdu.size()); + } + + void write_pdu(uint16_t rnti, srsran::const_byte_span pdu) + { + last_sdu_rnti = rnti; + last_pdu.resize(pdu.size()); + memcpy(last_pdu.data(), pdu.data(), pdu.size()); + } + + void ue_notify_rrc_reconf_complete(uint16_t rnti, bool outcome) { last_rrc_recnf_complete = outcome; } + + uint16_t last_sdu_rnti; + asn1::dyn_octstring last_pdu; + bool last_rrc_recnf_complete = false; +}; + /** * Run TS 38.331, 5.3.3 "RRC connection establishment" to completion * RRC actions: @@ -73,13 +101,32 @@ void test_rrc_nr_connection_establishment(srsran::task_scheduler& task_sched, rrc_nr& rrc_obj, rlc_nr_rrc_tester& rlc, mac_nr_dummy& mac, + ngap_rrc_tester& ngap, uint16_t rnti); +void test_rrc_nr_info_transfer(srsran::task_scheduler& task_sched, + rrc_nr& rrc_obj, + pdcp_nr_rrc_tester& pdcp, + ngap_rrc_tester& ngap, + uint16_t rnti); + void test_rrc_nr_security_mode_cmd(srsran::task_scheduler& task_sched, rrc_nr& rrc_obj, 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, + ngap_rrc_tester& ngap, + uint16_t rnti); + +void test_rrc_nr_2nd_reconfiguration(srsran::task_scheduler& task_sched, + rrc_nr& rrc_obj, + pdcp_nr_rrc_tester& pdcp, + ngap_rrc_tester& ngap, + uint16_t rnti); + } // namespace srsenb #endif // SRSRAN_RRC_NR_TEST_HELPERS_H diff --git a/srsue/hdr/stack/rrc/rrc_cell.h b/srsue/hdr/stack/rrc/rrc_cell.h index 33389cfee..f3485d33a 100644 --- a/srsue/hdr/stack/rrc/rrc_cell.h +++ b/srsue/hdr/stack/rrc/rrc_cell.h @@ -130,8 +130,6 @@ public: void set_sib3(const asn1::rrc_nr::sib3_s& sib3_); const asn1::rrc_nr::sib1_s* sib1ptr() const { return has_sib1() ? &sib1 : nullptr; } - const asn1::rrc_nr::sib2_s* sib2ptr() const { return has_sib2() ? &sib2 : nullptr; } - const asn1::rrc_nr::sib3_s* sib3ptr() const { return has_sib3() ? &sib3 : nullptr; } uint32_t get_cell_id() const { return (uint32_t)0xFFFF; } // TODO find the correct sib @@ -140,11 +138,7 @@ public: std::string to_string() const; - bool has_mcch = false; asn1::rrc_nr::sib1_s sib1 = {}; - asn1::rrc_nr::sib2_s sib2 = {}; - asn1::rrc_nr::sib3_s sib3 = {}; - asn1::rrc::mcch_msg_s mcch = {}; }; class meas_cell_eutra : public meas_cell diff --git a/srsue/hdr/stack/rrc/rrc_nr.h b/srsue/hdr/stack/rrc_nr/rrc_nr.h similarity index 86% rename from srsue/hdr/stack/rrc/rrc_nr.h rename to srsue/hdr/stack/rrc_nr/rrc_nr.h index 0bf8158c2..ced4cc1e8 100644 --- a/srsue/hdr/stack/rrc/rrc_nr.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr.h @@ -22,7 +22,8 @@ #ifndef SRSUE_RRC_NR_H #define SRSUE_RRC_NR_H -#include "nr/rrc_nr_config.h" +#include "../rrc/rrc_cell.h" +#include "rrc_nr_config.h" #include "srsran/adt/circular_map.h" #include "srsran/asn1/rrc_nr.h" #include "srsran/asn1/rrc_nr_utils.h" @@ -49,6 +50,7 @@ class rrc_nr final : public rrc_interface_phy_nr, public rrc_interface_rlc, public rrc_interface_mac, public rrc_nr_interface_rrc, + public rrc_nr_interface_nas_5g, public srsran::timer_callback { public: @@ -110,6 +112,13 @@ public: void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) final; void notify_pdcp_integrity_error(uint32_t lcid) final; + // NAS interface + int write_sdu(srsran::unique_byte_buffer_t sdu); + bool is_connected(); + int connection_request(srsran::nr_establishment_cause_t cause, srsran::unique_byte_buffer_t sdu); + uint16_t get_mcc(); + uint16_t get_mnc(); + // RRC (LTE) interface int get_eutra_nr_capabilities(srsran::byte_buffer_t* eutra_nr_caps); int get_nr_capabilities(srsran::byte_buffer_t* eutra_nr_caps); @@ -131,6 +140,9 @@ public: void set_phy_config_complete(bool status) final; private: + // senders + void send_ul_info_transfer(srsran::unique_byte_buffer_t nas_msg); + srsran::task_sched_handle task_sched; struct cmd_msg_t { enum { PDU, PCCH, PDU_MCH, RLF, PDU_BCCH_DLSCH, STOP } command; @@ -154,6 +166,8 @@ private: usim_interface_rrc_nr* usim = nullptr; stack_interface_rrc* stack = nullptr; + meas_cell_list meas_cells; + const uint32_t sim_measurement_timer_duration_ms = 250; uint32_t sim_measurement_carrier_freq_r15; srsran::timer_handler::unique_timer sim_measurement_timer; @@ -166,8 +180,7 @@ private: RRC_NR_STATE_N_ITEMS, }; const static char* rrc_nr_state_text[RRC_NR_STATE_N_ITEMS]; - - // rrc_nr_state_t state = RRC_NR_STATE_IDLE; + rrc_nr_state_t state = RRC_NR_STATE_IDLE; // Stores the state of the PHy configuration setting enum { @@ -214,30 +227,8 @@ private: typedef enum { mcg_srb1, en_dc_srb3, nr } reconf_initiator_t; - class connection_reconf_no_ho_proc - { - public: - explicit connection_reconf_no_ho_proc(rrc_nr* parent_); - srsran::proc_outcome_t init(const reconf_initiator_t initiator_, - const bool endc_release_and_add_r15, - const bool nr_secondary_cell_group_cfg_r15_present, - const asn1::dyn_octstring nr_secondary_cell_group_cfg_r15, - const bool sk_counter_r15_present, - const uint32_t sk_counter_r15, - const bool nr_radio_bearer_cfg1_r15_present, - const asn1::dyn_octstring nr_radio_bearer_cfg1_r15); - srsran::proc_outcome_t step() { return srsran::proc_outcome_t::yield; } - static const char* name() { return "NR Connection Reconfiguration"; } - srsran::proc_outcome_t react(const bool& config_complete); - void then(const srsran::proc_state_t& result); - - private: - // const - rrc_nr* rrc_ptr; - reconf_initiator_t initiator; - asn1::rrc_nr::rrc_recfg_s rrc_recfg; - asn1::rrc_nr::cell_group_cfg_s cell_group_cfg; - }; + // RRC procedures + class connection_reconf_no_ho_proc; srsran::proc_t conn_recfg_proc; diff --git a/srsue/hdr/stack/rrc/nr/rrc_nr_config.h b/srsue/hdr/stack/rrc_nr/rrc_nr_config.h similarity index 100% rename from srsue/hdr/stack/rrc/nr/rrc_nr_config.h rename to srsue/hdr/stack/rrc_nr/rrc_nr_config.h diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h b/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h new file mode 100644 index 000000000..9f5e65561 --- /dev/null +++ b/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h @@ -0,0 +1,52 @@ +/** + * + * \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/srslog/srslog.h" +#include "srsue/hdr/stack/rrc_nr/rrc_nr.h" + +#ifndef SRSRAN_RRC_NR_PROCEDURES_H +#define SRSRAN_RRC_NR_PROCEDURES_H + +namespace srsue { + +/******************************** + * Procedures + *******************************/ + +class rrc_nr::connection_reconf_no_ho_proc +{ +public: + explicit connection_reconf_no_ho_proc(rrc_nr* parent_); + srsran::proc_outcome_t init(const reconf_initiator_t initiator_, + const bool endc_release_and_add_r15, + const bool nr_secondary_cell_group_cfg_r15_present, + const asn1::dyn_octstring nr_secondary_cell_group_cfg_r15, + const bool sk_counter_r15_present, + const uint32_t sk_counter_r15, + const bool nr_radio_bearer_cfg1_r15_present, + const asn1::dyn_octstring nr_radio_bearer_cfg1_r15); + srsran::proc_outcome_t step() { return srsran::proc_outcome_t::yield; } + static const char* name() { return "NR Connection Reconfiguration"; } + srsran::proc_outcome_t react(const bool& config_complete); + void then(const srsran::proc_state_t& result); + +private: + // const + rrc_nr* rrc_ptr = nullptr; + reconf_initiator_t initiator; + asn1::rrc_nr::rrc_recfg_s rrc_recfg; + asn1::rrc_nr::cell_group_cfg_s cell_group_cfg; +}; + +} // namespace srsue + +#endif // SRSRAN_RRC_NR_PROCEDURES_H diff --git a/srsue/hdr/stack/ue_stack_base.h b/srsue/hdr/stack/ue_stack_base.h index 8bac5695d..d4749e96f 100644 --- a/srsue/hdr/stack/ue_stack_base.h +++ b/srsue/hdr/stack/ue_stack_base.h @@ -22,8 +22,8 @@ #ifndef SRSUE_UE_STACK_BASE_H #define SRSUE_UE_STACK_BASE_H -#include "rrc/nr/rrc_nr_config.h" #include "rrc/rrc_config.h" +#include "rrc_nr/rrc_nr_config.h" #include "srsue/hdr/stack/upper/nas_config.h" #include "srsue/hdr/ue_metrics_interface.h" #include "upper/gw.h" diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index 144652656..7980a8a49 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -29,7 +29,7 @@ #include "mac/mac.h" #include "mac_nr/mac_nr.h" #include "rrc/rrc.h" -#include "rrc/rrc_nr.h" +#include "rrc_nr/rrc_nr.h" #include "srsran/common/bearer_manager.h" #include "srsran/common/buffer_pool.h" #include "srsran/common/multiqueue.h" diff --git a/srsue/src/stack/CMakeLists.txt b/srsue/src/stack/CMakeLists.txt index 935530716..4149cd5b2 100644 --- a/srsue/src/stack/CMakeLists.txt +++ b/srsue/src/stack/CMakeLists.txt @@ -20,12 +20,13 @@ add_subdirectory(mac_common) add_subdirectory(mac) +add_subdirectory(mac_nr) add_subdirectory(rrc) +add_subdirectory(rrc_nr) add_subdirectory(upper) set(SOURCES ue_stack_lte.cc) add_library(srsue_stack STATIC ${SOURCES}) -add_subdirectory(mac_nr) set(SOURCES ue_stack_nr.cc) add_library(srsue_nr_stack STATIC ${SOURCES}) diff --git a/srsue/src/stack/rrc/CMakeLists.txt b/srsue/src/stack/rrc/CMakeLists.txt index d797aa4ef..d4aa33d27 100644 --- a/srsue/src/stack/rrc/CMakeLists.txt +++ b/srsue/src/stack/rrc/CMakeLists.txt @@ -21,8 +21,4 @@ add_subdirectory(test) set(SOURCES rrc.cc rrc_procedures.cc rrc_meas.cc rrc_cell.cc rrc_rlf_report.cc phy_controller.cc) -add_library(srsue_rrc STATIC ${SOURCES}) - -set(SOURCES rrc_nr.cc) -add_library(srsue_rrc_nr STATIC ${SOURCES}) - +add_library(srsue_rrc STATIC ${SOURCES}) \ No newline at end of file diff --git a/srsue/src/stack/rrc/rrc_cell.cc b/srsue/src/stack/rrc/rrc_cell.cc index ef501f6cc..fd89cab7c 100644 --- a/srsue/src/stack/rrc/rrc_cell.cc +++ b/srsue/src/stack/rrc/rrc_cell.cc @@ -180,6 +180,41 @@ uint16_t meas_cell_eutra::get_mnc() const return 0; } +uint16_t meas_cell_nr::get_mcc() const +{ + uint16_t mcc = 0; + if (has_valid_sib1) { + if (sib1.cell_access_related_info.plmn_id_list.size() > 0) { + // PLMN ID list is nested twice + if (sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list.size() > 0) { + if (sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list[0].mcc_present) { + if (srsran::bytes_to_mcc(&sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list[0].mcc[0], &mcc)) { + // successfully read MCC + } + } + } + } + } + return mcc; +} + +uint16_t meas_cell_nr::get_mnc() const +{ + uint16_t mnc = 0; + if (has_valid_sib1) { + if (sib1.cell_access_related_info.plmn_id_list.size() > 0) { + if (sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list.size() > 0) { + if (srsran::bytes_to_mnc(&sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list[0].mnc[0], + &mnc, + sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list[0].mnc.size())) { + // successfully read MNC + } + } + } + } + return mnc; +} + /********************************************* * Neighbour Cell List ********************************************/ diff --git a/srsue/src/stack/rrc/test/CMakeLists.txt b/srsue/src/stack/rrc/test/CMakeLists.txt index 7567f75a9..0fce6c57e 100644 --- a/srsue/src/stack/rrc/test/CMakeLists.txt +++ b/srsue/src/stack/rrc/test/CMakeLists.txt @@ -36,17 +36,4 @@ add_test(rrc_cell_test rrc_cell_test) add_executable(rrc_rlf_report_test rrc_rlf_report_test.cc) target_link_libraries(rrc_rlf_report_test srsue_rrc srsue_upper srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1) -add_test(rrc_rlf_report_test rrc_rlf_report_test) - -add_executable(ue_rrc_nr_test ue_rrc_nr_test.cc) -target_link_libraries(ue_rrc_nr_test srsue_rrc_nr srsue_upper srsran_common srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1) - -######################################################################## -# Option to run command after build (useful for remote builds) -######################################################################## -if (NOT ${BUILD_CMD} STREQUAL "") - message(STATUS "Added custom post-build command: ${BUILD_CMD}") - add_custom_command(TARGET ip_test POST_BUILD COMMAND ${BUILD_CMD}) -else(NOT ${BUILD_CMD} STREQUAL "") - message(STATUS "No post-build command defined") -endif (NOT ${BUILD_CMD} STREQUAL "") +add_test(rrc_rlf_report_test rrc_rlf_report_test) \ No newline at end of file diff --git a/srsue/src/stack/rrc/test/rrc_meas_test.cc b/srsue/src/stack/rrc/test/rrc_meas_test.cc index d36a1cb72..19efcbeea 100644 --- a/srsue/src/stack/rrc/test/rrc_meas_test.cc +++ b/srsue/src/stack/rrc/test/rrc_meas_test.cc @@ -26,7 +26,7 @@ #include "srsran/upper/pdcp.h" #include "srsue/hdr/stack/rrc/rrc.h" #include "srsue/hdr/stack/rrc/rrc_meas.h" -#include "srsue/hdr/stack/rrc/rrc_nr.h" +#include "srsue/hdr/stack/rrc_nr/rrc_nr.h" #include "srsue/hdr/stack/upper/nas.h" #include diff --git a/srsue/src/stack/rrc_nr/CMakeLists.txt b/srsue/src/stack/rrc_nr/CMakeLists.txt new file mode 100644 index 000000000..5bbeafd4a --- /dev/null +++ b/srsue/src/stack/rrc_nr/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# 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. +# + +add_subdirectory(test) + +set(SOURCES rrc_nr.cc rrc_nr_procedures.cc ../rrc/rrc_cell.cc) +add_library(srsue_rrc_nr STATIC ${SOURCES}) \ No newline at end of file diff --git a/srsue/src/stack/rrc/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc similarity index 92% rename from srsue/src/stack/rrc/rrc_nr.cc rename to srsue/src/stack/rrc_nr/rrc_nr.cc index 4c4fa8102..22894a59f 100644 --- a/srsue/src/stack/rrc/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -19,19 +19,15 @@ * */ -#include "srsue/hdr/stack/rrc/rrc_nr.h" +#include "srsue/hdr/stack/rrc_nr/rrc_nr.h" #include "srsran/common/band_helper.h" #include "srsran/common/security.h" #include "srsran/common/standard_streams.h" #include "srsran/interfaces/ue_pdcp_interfaces.h" #include "srsran/interfaces/ue_rlc_interfaces.h" +#include "srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h" #include "srsue/hdr/stack/upper/usim.h" -#define Error(fmt, ...) rrc_ptr->logger.error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) -#define Warning(fmt, ...) rrc_ptr->logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) -#define Info(fmt, ...) rrc_ptr->logger.info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) -#define Debug(fmt, ...) rrc_ptr->logger.debug("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) - using namespace asn1::rrc_nr; using namespace asn1; using namespace srsran; @@ -40,7 +36,7 @@ namespace srsue { const char* rrc_nr::rrc_nr_state_text[] = {"IDLE", "CONNECTED", "CONNECTED-INACTIVE"}; 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) + logger(srslog::fetch_basic_logger("RRC-NR")), task_sched(task_sched_), conn_recfg_proc(this), meas_cells(task_sched_) {} rrc_nr::~rrc_nr() = default; @@ -218,6 +214,44 @@ void rrc_nr::write_pdu_pcch(srsran::unique_byte_buffer_t pdu) {} void rrc_nr::write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) {} void rrc_nr::notify_pdcp_integrity_error(uint32_t lcid) {} +// NAS interface +int rrc_nr::write_sdu(srsran::unique_byte_buffer_t sdu) +{ + if (state == RRC_NR_STATE_IDLE) { + logger.warning("Received ULInformationTransfer SDU when in IDLE"); + return SRSRAN_ERROR; + } + send_ul_info_transfer(std::move(sdu)); + return SRSRAN_SUCCESS; +} + +bool rrc_nr::is_connected() +{ + return false; +} + +int rrc_nr::connection_request(srsran::nr_establishment_cause_t cause, srsran::unique_byte_buffer_t sdu) +{ + return SRSRAN_SUCCESS; +} + +uint16_t rrc_nr::get_mcc() +{ + return meas_cells.serving_cell().get_mcc(); +} + +uint16_t rrc_nr::get_mnc() +{ + return meas_cells.serving_cell().get_mnc(); +} + +// Senders +void rrc_nr::send_ul_info_transfer(unique_byte_buffer_t nas_msg) +{ + logger.warning("%s not implemented yet.", __FUNCTION__); +} + +// EUTRA-RRC interface int rrc_nr::get_eutra_nr_capabilities(srsran::byte_buffer_t* eutra_nr_caps_pdu) { struct ue_mrdc_cap_s mrdc_cap; @@ -1557,133 +1591,4 @@ void rrc_nr::set_phy_config_complete(bool status) phy_cfg_state = PHY_CFG_STATE_NONE; } -/* Procedures */ -rrc_nr::connection_reconf_no_ho_proc::connection_reconf_no_ho_proc(rrc_nr* parent_) : rrc_ptr(parent_), initiator(nr) {} - -proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator_t initiator_, - const bool endc_release_and_add_r15, - const bool nr_secondary_cell_group_cfg_r15_present, - const asn1::dyn_octstring nr_secondary_cell_group_cfg_r15, - const bool sk_counter_r15_present, - const uint32_t sk_counter_r15, - const bool nr_radio_bearer_cfg1_r15_present, - const asn1::dyn_octstring nr_radio_bearer_cfg1_r15) -{ - Info("Starting..."); - initiator = initiator_; - - rrc_recfg_s rrc_recfg; - cell_group_cfg_s cell_group_cfg; - radio_bearer_cfg_s radio_bearer_cfg; - asn1::SRSASN_CODE err; - - if (nr_secondary_cell_group_cfg_r15_present) { - cbit_ref bref(nr_secondary_cell_group_cfg_r15.data(), nr_secondary_cell_group_cfg_r15.size()); - err = rrc_recfg.unpack(bref); - if (err != asn1::SRSASN_SUCCESS) { - Error("Could not unpack NR reconfiguration message."); - return proc_outcome_t::error; - } - - rrc_ptr->log_rrc_message( - "RRC NR Reconfiguration", Rx, nr_secondary_cell_group_cfg_r15, rrc_recfg, "NR Secondary Cell Group Cfg R15"); - - if (rrc_recfg.crit_exts.type() != asn1::rrc_nr::rrc_recfg_s::crit_exts_c_::types::rrc_recfg) { - Error("Reconfiguration does not contain Secondary Cell Group Config"); - return proc_outcome_t::error; - } - - if (not rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group_present) { - Error("Reconfiguration does not contain Secondary Cell Group Config"); - return proc_outcome_t::error; - } - - cbit_ref bref0(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.data(), - rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.size()); - - err = cell_group_cfg.unpack(bref0); - if (err != asn1::SRSASN_SUCCESS) { - Error("Could not unpack cell group message message."); - return proc_outcome_t::error; - } - - rrc_ptr->log_rrc_message("RRC NR Reconfiguration", - Rx, - rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group, - cell_group_cfg, - "Secondary Cell Group Config"); - - Info("Applying Cell Group Cfg"); - if (!rrc_ptr->apply_cell_group_cfg(cell_group_cfg)) { - return proc_outcome_t::error; - } - } - - if (sk_counter_r15_present) { - Info("Applying Cell Group Cfg"); - if (!rrc_ptr->configure_sk_counter((uint16_t)sk_counter_r15)) { - return proc_outcome_t::error; - } - } - - if (nr_radio_bearer_cfg1_r15_present) { - cbit_ref bref1(nr_radio_bearer_cfg1_r15.data(), nr_radio_bearer_cfg1_r15.size()); - - err = radio_bearer_cfg.unpack(bref1); - if (err != asn1::SRSASN_SUCCESS) { - Error("Could not unpack radio bearer config."); - return proc_outcome_t::error; - } - - rrc_ptr->log_rrc_message( - "RRC NR Reconfiguration", Rx, nr_radio_bearer_cfg1_r15, radio_bearer_cfg, "Radio Bearer Config R15"); - - Info("Applying Radio Bearer Cfg"); - if (!rrc_ptr->apply_radio_bearer_cfg(radio_bearer_cfg)) { - return proc_outcome_t::error; - } - } - - return proc_outcome_t::success; -} - -proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::react(const bool& config_complete) -{ - if (not config_complete) { - Error("NR reconfiguration failed"); - return proc_outcome_t::error; - } - - // TODO phy ctrl - // in case there are scell to configure, wait for second phy configuration - // if (not rrc_ptr->phy_ctrl->is_config_pending()) { - // return proc_outcome_t::yield; - // } - - Info("Reconfig NR return successful"); - return proc_outcome_t::success; -} - -void rrc_nr::connection_reconf_no_ho_proc::then(const srsran::proc_state_t& result) -{ - if (result.is_success()) { - Info("Finished %s successfully", name()); - srsran::console("RRC NR reconfiguration successful.\n"); - rrc_ptr->rrc_eutra->nr_rrc_con_reconfig_complete(true); - } else { - // 5.3.5.8.2 Inability to comply with RRCReconfiguration - switch (initiator) { - case reconf_initiator_t::mcg_srb1: - rrc_ptr->rrc_eutra->nr_notify_reconfiguration_failure(); - break; - default: - Warning("Reconfiguration failure not implemented for initiator %d", initiator); - break; - } - srsran::console("RRC NR reconfiguration failed.\n"); - Warning("Finished %s with failure", name()); - } - return; -} - } // namespace srsue diff --git a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc new file mode 100644 index 000000000..cfae613e0 --- /dev/null +++ b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc @@ -0,0 +1,160 @@ +/** + * + * \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/rrc_nr/rrc_nr_procedures.h" +#include "srsran/common/standard_streams.h" + +#define Error(fmt, ...) rrc_ptr->logger.error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) +#define Warning(fmt, ...) rrc_ptr->logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) +#define Info(fmt, ...) rrc_ptr->logger.info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) +#define Debug(fmt, ...) rrc_ptr->logger.debug("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) + +using namespace asn1::rrc_nr; +using namespace asn1; +using namespace srsran; + +namespace srsue { + +rrc_nr::connection_reconf_no_ho_proc::connection_reconf_no_ho_proc(rrc_nr* parent_) : rrc_ptr(parent_), initiator(nr) {} + +proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator_t initiator_, + const bool endc_release_and_add_r15, + const bool nr_secondary_cell_group_cfg_r15_present, + const asn1::dyn_octstring nr_secondary_cell_group_cfg_r15, + const bool sk_counter_r15_present, + const uint32_t sk_counter_r15, + const bool nr_radio_bearer_cfg1_r15_present, + const asn1::dyn_octstring nr_radio_bearer_cfg1_r15) +{ + Info("Starting..."); + initiator = initiator_; + + rrc_recfg_s rrc_recfg; + cell_group_cfg_s cell_group_cfg; + radio_bearer_cfg_s radio_bearer_cfg; + asn1::SRSASN_CODE err; + + if (nr_secondary_cell_group_cfg_r15_present) { + cbit_ref bref(nr_secondary_cell_group_cfg_r15.data(), nr_secondary_cell_group_cfg_r15.size()); + err = rrc_recfg.unpack(bref); + if (err != asn1::SRSASN_SUCCESS) { + Error("Could not unpack NR reconfiguration message."); + return proc_outcome_t::error; + } + +#if 0 + rrc_ptr->log_rrc_message( + "RRC NR Reconfiguration", Rx, nr_secondary_cell_group_cfg_r15, rrc_recfg, "NR Secondary Cell Group Cfg R15"); +#endif + if (rrc_recfg.crit_exts.type() != asn1::rrc_nr::rrc_recfg_s::crit_exts_c_::types::rrc_recfg) { + Error("Reconfiguration does not contain Secondary Cell Group Config"); + return proc_outcome_t::error; + } + + if (not rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group_present) { + Error("Reconfiguration does not contain Secondary Cell Group Config"); + return proc_outcome_t::error; + } + + cbit_ref bref0(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.data(), + rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.size()); + + err = cell_group_cfg.unpack(bref0); + if (err != asn1::SRSASN_SUCCESS) { + Error("Could not unpack cell group message message."); + return proc_outcome_t::error; + } + +#if 0 + rrc_ptr->log_rrc_message("RRC NR Reconfiguration", + Rx, + rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group, + cell_group_cfg, + "Secondary Cell Group Config"); +#endif + + Info("Applying Cell Group Cfg"); + if (!rrc_ptr->apply_cell_group_cfg(cell_group_cfg)) { + return proc_outcome_t::error; + } + } + + if (sk_counter_r15_present) { + Info("Applying Cell Group Cfg"); + if (!rrc_ptr->configure_sk_counter((uint16_t)sk_counter_r15)) { + return proc_outcome_t::error; + } + } + + if (nr_radio_bearer_cfg1_r15_present) { + cbit_ref bref1(nr_radio_bearer_cfg1_r15.data(), nr_radio_bearer_cfg1_r15.size()); + + err = radio_bearer_cfg.unpack(bref1); + if (err != asn1::SRSASN_SUCCESS) { + Error("Could not unpack radio bearer config."); + return proc_outcome_t::error; + } + +#if 0 + rrc_ptr->log_rrc_message( + "RRC NR Reconfiguration", Rx, nr_radio_bearer_cfg1_r15, radio_bearer_cfg, "Radio Bearer Config R15"); +#endif + + Info("Applying Radio Bearer Cfg"); + if (!rrc_ptr->apply_radio_bearer_cfg(radio_bearer_cfg)) { + return proc_outcome_t::error; + } + } + + return proc_outcome_t::success; +} + +proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::react(const bool& config_complete) +{ + if (not config_complete) { + Error("NR reconfiguration failed"); + return proc_outcome_t::error; + } + + // TODO phy ctrl + // in case there are scell to configure, wait for second phy configuration + // if (not rrc_ptr->phy_ctrl->is_config_pending()) { + // return proc_outcome_t::yield; + // } + + Info("Reconfig NR return successful"); + return proc_outcome_t::success; +} + +void rrc_nr::connection_reconf_no_ho_proc::then(const srsran::proc_state_t& result) +{ + if (result.is_success()) { + Info("Finished %s successfully", name()); + srsran::console("RRC NR reconfiguration successful.\n"); + rrc_ptr->rrc_eutra->nr_rrc_con_reconfig_complete(true); + } else { + // 5.3.5.8.2 Inability to comply with RRCReconfiguration + switch (initiator) { + case reconf_initiator_t::mcg_srb1: + rrc_ptr->rrc_eutra->nr_notify_reconfiguration_failure(); + break; + default: + Warning("Reconfiguration failure not implemented for initiator %d", initiator); + break; + } + srsran::console("RRC NR reconfiguration failed.\n"); + Warning("Finished %s with failure", name()); + } + return; +} + +} // namespace srsue diff --git a/srsue/src/stack/rrc_nr/test/CMakeLists.txt b/srsue/src/stack/rrc_nr/test/CMakeLists.txt new file mode 100644 index 000000000..1e431d46a --- /dev/null +++ b/srsue/src/stack/rrc_nr/test/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# 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. +# + +add_executable(ue_rrc_nr_test ue_rrc_nr_test.cc) +target_link_libraries(ue_rrc_nr_test srsue_rrc srsue_rrc_nr srsue_upper srsran_common srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1) \ No newline at end of file diff --git a/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc b/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc similarity index 99% rename from srsue/src/stack/rrc/test/ue_rrc_nr_test.cc rename to srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc index 7fc102a5a..dbe1a8ee1 100644 --- a/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc +++ b/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc @@ -25,7 +25,7 @@ #include "srsran/interfaces/ue_pdcp_interfaces.h" #include "srsran/interfaces/ue_rlc_interfaces.h" #include "srsran/interfaces/ue_usim_interfaces.h" -#include "srsue/hdr/stack/rrc/rrc_nr.h" +#include "srsue/hdr/stack/rrc_nr/rrc_nr.h" using namespace srsue; diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index 45f7e3275..4e1f25eeb 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -21,7 +21,7 @@ #include "srsue/hdr/stack/ue_stack_nr.h" #include "srsran/srsran.h" -#include "srsue/hdr/stack/rrc/rrc_nr.h" +#include "srsue/hdr/stack/rrc_nr/rrc_nr.h" using namespace srsran; diff --git a/test/phy/nr_phy_test.cc b/test/phy/nr_phy_test.cc index 49f03750e..020701a94 100644 --- a/test/phy/nr_phy_test.cc +++ b/test/phy/nr_phy_test.cc @@ -41,13 +41,16 @@ static double assert_pucch_snr_min = 0.000; test_bench::args_t::args_t(int argc, char** argv) { - std::string reference_cfg_str = ""; - bpo::options_description options("Test bench options"); + std::string config_file; + std::string reference_cfg_str; + bpo::options_description options; + bpo::options_description options_tb("Test bench options"); bpo::options_description options_gnb_stack("gNb stack and scheduling related options"); bpo::options_description options_gnb_phy("gNb PHY related options"); bpo::options_description options_ue_stack("UE stack options"); bpo::options_description options_ue_phy("UE stack options"); bpo::options_description options_assertion("Test assertions"); + bpo::options_description options_conf_file("Configuration file"); uint16_t rnti = 17921; @@ -55,10 +58,10 @@ test_bench::args_t::args_t(int argc, char** argv) gnb_stack.pusch.slots = "6,7,8,9"; // clang-format off - options.add_options() + options_tb.add_options() ("rnti", bpo::value(&rnti)->default_value(rnti), "UE RNTI") ("duration", bpo::value(&durations_slots)->default_value(durations_slots), "Test duration in slots") - ("lib.log.level", bpo::value(&phy_lib_log_level)->default_value(phy_lib_log_level), "PHY librray log level") + ("lib.log.level", bpo::value(&phy_lib_log_level)->default_value(phy_lib_log_level), "PHY library log level") ("reference", bpo::value(&reference_cfg_str)->default_value(reference_cfg_str), "Reference PHY configuration arguments") ("dl_channel.awgn_enable", bpo::value(&dl_channel.awgn_enable)->default_value(dl_channel.awgn_enable), "DL Channel AWGN enable / disable") ("dl_channel.awgn_snr", bpo::value(&dl_channel.awgn_snr_dB)->default_value(dl_channel.awgn_snr_dB), "DL Channel AWGN SNR in dB") @@ -114,14 +117,20 @@ test_bench::args_t::args_t(int argc, char** argv) ("assert.pucch.snr.min", bpo::value(&assert_pucch_snr_min)->default_value(assert_pucch_snr_min), "PUCCH DMRS minimum SNR allowed threshold") ; - options.add(options_gnb_stack).add(options_gnb_phy).add(options_ue_stack).add(options_ue_phy).add_options() + options_conf_file.add_options() + ("config_file", bpo::value(&config_file), "Configuration file") + ; + bpo::positional_options_description p; + p.add("config_file", -1); + + options.add(options_tb).add(options_assertion).add(options_gnb_stack).add(options_gnb_phy).add(options_ue_stack).add(options_ue_phy).add(options_conf_file).add_options() ("help", "Show this message") ; // clang-format on bpo::variables_map vm; try { - bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm); + bpo::store(bpo::command_line_parser(argc, argv).options(options).positional(p).run(), vm); bpo::notify(vm); // Apply the High Speed Train args to the DL channel as well @@ -136,14 +145,35 @@ test_bench::args_t::args_t(int argc, char** argv) // help option was given or error - print usage and exit if (vm.count("help")) { std::cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << std::endl << std::endl; - std::cout << options << std::endl << std::endl; - return; + std::cout << options_tb << std::endl << options_assertion << std::endl; + std::cout << options_gnb_phy << std::endl << options_gnb_stack << std::endl; + std::cout << options_ue_phy << std::endl << options_ue_stack << std::endl; + exit(0); + } + + // if config file given + if (vm.count("config_file") != 0U) { + std::cout << "Reading configuration file " << config_file << "..." << std::endl; + std::ifstream conf(config_file.c_str(), std::ios::in); + if (conf.fail()) { + std::cout << "Failed to read configuration file " << config_file << " - exiting" << std::endl; + exit(1); + } + + // parse config file and handle errors gracefully + try { + bpo::store(bpo::parse_config_file(conf, options), vm); + bpo::notify(vm); + } catch (const boost::program_options::error& e) { + std::cerr << e.what() << std::endl; + exit(1); + } } // Load default reference configuration phy_cfg = srsran::phy_cfg_nr_default_t(srsran::phy_cfg_nr_default_t::reference_cfg_t(reference_cfg_str)); - // Calulate the DL signal power from the number of PRBs + // Calculate the DL signal power from the number of PRBs dl_channel.awgn_signal_power_dBfs = srsran_gnb_dl_get_maximum_signal_power_dBfs(phy_cfg.carrier.nof_prb); // Reverses the Doppler shift for the UL @@ -274,7 +304,7 @@ int main(int argc, char** argv) "EPRE (dB)", metrics.gnb_stack.pucch.epre_db_avg, metrics.gnb_stack.pucch.epre_db_min, - metrics.gnb_stack.pucch.epre_db_min); + metrics.gnb_stack.pucch.epre_db_max); srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n", "RSRP (dB)", metrics.gnb_stack.pucch.rsrp_db_avg, @@ -341,7 +371,7 @@ int main(int argc, char** argv) "EPRE (dB)", metrics.gnb_stack.pusch.epre_db_avg, metrics.gnb_stack.pusch.epre_db_min, - metrics.gnb_stack.pusch.epre_db_min); + metrics.gnb_stack.pusch.epre_db_max); srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n", "RSRP (dB)", metrics.gnb_stack.pusch.rsrp_db_avg, diff --git a/test/phy/test_bench.h b/test/phy/test_bench.h index 0ec017668..1dc9c45e3 100644 --- a/test/phy/test_bench.h +++ b/test/phy/test_bench.h @@ -168,7 +168,7 @@ public: // Run the UL channel simulator ul_channel.run(gnb_rx_buffers.data(), gnb_rx_buffers.data(), (uint32_t)sf_sz, gnb_time.get(0)); - // Set gnb context + // Set gNb context srsran::phy_common_interface::worker_context_t gnb_context; gnb_context.sf_idx = slot_idx; gnb_context.worker_ptr = gnb_worker; @@ -198,7 +198,7 @@ public: // Run the DL channel simulator dl_channel.run(ue_rx_buffers.data(), ue_rx_buffers.data(), (uint32_t)sf_sz, ue_time.get(0)); - // Set gnb context + // Set UE context srsran::phy_common_interface::worker_context_t ue_context; ue_context.sf_idx = slot_idx; ue_context.worker_ptr = ue_worker;