Merge branch 'next' into agpl_next

This commit is contained in:
Codebot 2021-12-03 09:27:03 +01:00 committed by Your Name
commit fc3ac4d491
72 changed files with 1401 additions and 487 deletions

View File

@ -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)

View File

@ -27,8 +27,8 @@
#include "srsran/common/rwlock_guard.h"
#include "srsran/srslog/srslog.h"
#include <map>
#include <unordered_map>
#include <stdint.h>
#include <unordered_map>
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);

View File

@ -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

View File

@ -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

View File

@ -28,7 +28,7 @@
namespace srsran {
/**
* @brief Descibes a physical layer common interface
* @brief Describes a physical layer common interface
*/
class phy_common_interface
{

View File

@ -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);

View File

@ -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);

View File

@ -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<iterator,bool>
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;

View File

@ -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 &&

View File

@ -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:

View File

@ -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);

View File

@ -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)
{

View File

@ -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",

View File

@ -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");

View File

@ -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 $<TARGET_OBJECTS:srsran_rf_object>)
add_library(srsran_rf_shared SHARED $<TARGET_OBJECTS:srsran_rf_object>)
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)

View File

@ -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)) {

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
}

View File

@ -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<uint32_t, srsran::unique_byte_buffer_t> 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

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<uint32_t, srsran::unique_byte_buffer_t> 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)),

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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));

View File

@ -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) {}
};

View File

@ -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<srsenb::gtpu> gtpu;
// std::unique_ptr<sdap> m_sdap;
std::unique_ptr<enb_bearer_manager> bearer_manager;
std::unique_ptr<gtpu_pdcp_adapter> gtpu_adapter;
// state
std::atomic<bool> running = {false};
};

View File

@ -104,6 +104,20 @@ struct bwp_params_t {
srsran::optional_vector<bwp_cce_pos_list> 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<prb_bitmap> used_common_prb_masks;
};
/// Structure packing a single cell config params, and sched args

View File

@ -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 {

View File

@ -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<uint32_t> ran_ue_ngap_id = {},
srsran::optional<uint32_t> 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

View File

@ -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 = {};

View File

@ -65,18 +65,24 @@ public:
int reset_pdu_sessions(uint16_t rnti);
private:
gtpu_interface_rrc* gtpu = nullptr;
std::map<uint8_t, pdu_session_t> pdu_session_list;
srslog::basic_logger& logger;
using pdu_session_list_t = std::map<uint8_t, pdu_session_t>;
const pdu_session_list_t& pdu_sessions() const { return pdu_session_list; }
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);
private:
gtpu_interface_rrc* gtpu = nullptr;
pdu_session_list_t pdu_session_list;
srslog::basic_logger& logger;
std::map<uint32_t, uint32_t> 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);
uint8_t allocate_lcid(uint32_t rnti);
};
} // namespace srsenb
#endif // SRSENB_NGAP_UE_BEARER_MANAGER_H
#endif // SRSENB_NGAP_UE_BEARER_MANAGER_H

View File

@ -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;

View File

@ -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<srsran::CIPHERING_ALGORITHM_ID_NR_ENUM, srsran::CIPHERING_ALGORITHM_ID_NR_N_ITEMS> nea_preference_list;

View File

@ -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);

View File

@ -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 <srsran/interfaces/enb_metrics_interface.h>
@ -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

View File

@ -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<dl_sched_rar_info_t> msg3_grants{rar.msg3_grant};

View File

@ -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);
}
}
}

View File

@ -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<bool> prbs{pdsch.sch.grant.prb_idx, pdsch.sch.grant.prb_idx + pdsch.sch.grant.nof_prb};
srsran::const_span<bool> 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<bool> prbs{pdsch.sch.grant.prb_idx, pdsch.sch.grant.prb_idx + pdsch.sch.grant.nof_prb};
srsran::const_span<bool> 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",

View File

@ -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)

View File

@ -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

View File

@ -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)) {

View File

@ -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
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

View File

@ -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(

View File

@ -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) {}

View File

@ -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;

View File

@ -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;

View File

@ -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;
// 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();
// Update lower layers
// 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) {
// add PDCP bearers
update_pdcp_bearers(ies.radio_bearer_cfg, master_cell_group);
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);
// 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
// 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] =

View File

@ -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 <iostream>
@ -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<srsran::log_sink_spy>(new srsran::log_sink_spy(srslog::get_default_log_formatter())))) {
return SRSRAN_ERROR;
}
auto* spy = static_cast<srsran::log_sink_spy*>(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;
}

View File

@ -21,6 +21,9 @@
#include "rrc_nr_test_helpers.h"
#include "srsran/common/test_common.h"
#include <string>
#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<false> for the expected MSG
asn1::unbounded_octstring<false> 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<false> 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<false> 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<false> 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<false> 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

View File

@ -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

View File

@ -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

View File

@ -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_cell_nr> 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<connection_reconf_no_ho_proc> conn_recfg_proc;

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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})

View File

@ -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})

View File

@ -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
********************************************/

View File

@ -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)

View File

@ -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 <iostream>

View File

@ -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})

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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<uint16_t>(&rnti)->default_value(rnti), "UE RNTI")
("duration", bpo::value<uint64_t>(&durations_slots)->default_value(durations_slots), "Test duration in slots")
("lib.log.level", bpo::value<std::string>(&phy_lib_log_level)->default_value(phy_lib_log_level), "PHY librray log level")
("lib.log.level", bpo::value<std::string>(&phy_lib_log_level)->default_value(phy_lib_log_level), "PHY library log level")
("reference", bpo::value<std::string>(&reference_cfg_str)->default_value(reference_cfg_str), "Reference PHY configuration arguments")
("dl_channel.awgn_enable", bpo::value<bool>(&dl_channel.awgn_enable)->default_value(dl_channel.awgn_enable), "DL Channel AWGN enable / disable")
("dl_channel.awgn_snr", bpo::value<float>(&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<double>(&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<std::string>(&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,

View File

@ -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;