Merge branch 'next' into agpl_next

This commit is contained in:
Codebot 2022-07-24 21:12:22 +00:00 committed by SRS codebot
commit 38a520b3c2
20 changed files with 658 additions and 50 deletions

View File

@ -1,35 +1,44 @@
name: C/C++ CI
on: push
jobs:
x86_ubuntu18_build:
name: Build and test on x86 Ubuntu 18.04
strategy:
matrix:
compiler: [gcc, clang]
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v1
- name: Build srsRAN on x86 Ubuntu 18.04
run: |
sudo apt update
sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind
mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja && ctest
aarch64_ubuntu18_build:
runs-on: ubuntu-18.04
name: Build on aarch64
x86_ubuntu_build:
name: Build on x86
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, ubuntu-18.04]
compiler: [gcc, clang]
steps:
- uses: actions/checkout@v1
- name: Build srsRAN on aarch64
- uses: actions/checkout@v3
- name: Build srsRAN on x86 ${{ matrix.os }}
run: |
sudo apt update
sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind
mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja && ctest
aarch64_ubuntu_build:
name: Build on aarch64
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, ubuntu-18.04]
compiler: [gcc, clang]
include:
- os: ubuntu-20.04
distro: ubuntu20.04
- os: ubuntu-18.04
distro: ubuntu18.04
steps:
- uses: actions/checkout@v3
- name: Build srsRAN on aarch64 ${{ matrix.os }}
uses: uraimo/run-on-arch-action@master
with:
architecture: aarch64
distribution: ubuntu18.04
arch: aarch64
distro: ${{ matrix.distro }}
run: |
export CTEST_PARALLEL_LEVEL=$(nproc --all)
apt update
apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev ninja-build
ls -l && pwd && mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja
ls -l && pwd && mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja

View File

@ -95,6 +95,7 @@ private:
void retransmit_pdu(uint32_t sn);
// Helpers
bool window_full();
bool poll_required();
bool do_status();
void check_sn_reached_max_retx(uint32_t sn);

View File

@ -319,6 +319,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_id_ie(uint8** ie_ptr, LIBLTE_MME_MOBI
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8* id;
uint32* id32;
uint32 length;
uint32 i;
bool odd = false;
@ -338,22 +339,35 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_id_ie(uint8** ie_ptr, LIBLTE_MME_MOBI
} else if (LIBLTE_MME_MOBILE_ID_TYPE_IMEISV == mobile_id->type_of_id) {
id = mobile_id->imeisv;
odd = false;
} else if (LIBLTE_MME_MOBILE_ID_TYPE_TMSI == mobile_id->type_of_id) {
id32 = &mobile_id->tmsi;
odd = false;
} else {
// TODO: Not handling these IDs
return (err);
}
id[0] = **ie_ptr >> 4;
*ie_ptr += 1;
for (i = 0; i < 7; i++) {
id[i * 2 + 1] = (*ie_ptr)[i] & 0x0F;
id[i * 2 + 2] = (*ie_ptr)[i] >> 4;
}
if (odd) {
*ie_ptr += 7;
if (mobile_id->type_of_id != LIBLTE_MME_MOBILE_ID_TYPE_TMSI) {
id[0] = **ie_ptr >> 4;
*ie_ptr += 1;
for (i = 0; i < 7; i++) {
id[i * 2 + 1] = (*ie_ptr)[i] & 0x0F;
id[i * 2 + 2] = (*ie_ptr)[i] >> 4;
}
if (odd) {
*ie_ptr += 7;
} else {
id[i * 2 + 1] = (*ie_ptr)[i] & 0xF;
*ie_ptr += 8;
}
} else {
id[i * 2 + 1] = (*ie_ptr)[i] & 0xF;
*ie_ptr += 8;
*ie_ptr += 1;
uint32 tmsi = 0;
for (i = 0; i < 4; i++) {
tmsi += ((*ie_ptr)[i] & 0xFF) << ((3 - i) * 8);
}
*id32 = tmsi;
*ie_ptr += 4;
}
err = LIBLTE_SUCCESS;
@ -1380,12 +1394,13 @@ liblte_mme_unpack_eps_network_feature_support_ie(uint8** ie_ptr, LIBLTE_MME_EPS_
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if (ie_ptr != NULL && eps_nfs != NULL) {
int ie_len = *ie_ptr[0];
eps_nfs->esrps = ((*ie_ptr)[1] >> 5) & 0x01;
eps_nfs->cs_lcs = (LIBLTE_MME_CS_LCS_ENUM)(((*ie_ptr)[1] >> 3) & 0x03);
eps_nfs->epc_lcs = ((*ie_ptr)[1] >> 2) & 0x01;
eps_nfs->emc_bs = ((*ie_ptr)[1] >> 1) & 0x01;
eps_nfs->ims_vops = (*ie_ptr)[1] & 0x01;
*ie_ptr += 2;
*ie_ptr += (ie_len + 1);
err = LIBLTE_SUCCESS;
}

View File

@ -30,7 +30,11 @@ add_test(viterbi_40_2 viterbi_test -n 1000 -s 1 -l 40 -t -e 2.0)
add_test(viterbi_40_3 viterbi_test -n 1000 -s 1 -l 40 -t -e 3.0)
add_test(viterbi_40_4 viterbi_test -n 1000 -s 1 -l 40 -t -e 4.5)
add_test(viterbi_1000_0 viterbi_test -n 100 -s 1 -l 1000 -t -e 0.0)
if (HAVE_AVX2)
# The accuracy of the 8-bit implementation of the Viterbi decoder used on
# non-AVX2 machines falls below the theoretical accuracy at 0dB.
add_test(viterbi_1000_0 viterbi_test -n 100 -s 1 -l 1000 -t -e 0.0)
endif()
add_test(viterbi_1000_2 viterbi_test -n 100 -s 1 -l 1000 -t -e 2.0)
add_test(viterbi_1000_3 viterbi_test -n 100 -s 1 -l 1000 -t -e 3.0)
add_test(viterbi_1000_4 viterbi_test -n 100 -s 1 -l 1000 -t -e 4.5)

View File

@ -211,8 +211,9 @@ add_executable(pdcch_test pdcch_test.c)
target_link_libraries(pdcch_test srsran_phy)
foreach (nof_prb 6 15 25 50 75 100)
# Currently, the ARM platforms srsRAN has been tested are not capable of running 100PRB. So, skip 100 PRB in ARM
if (HAVE_NEON AND (${nof_prb} EQUAL 100))
# Currently, the ARM and SSE platforms srsRAN has been tested are not capable of running 100PRB. So, skip 100 PRB in
# ARM and SSE.
if ((HAVE_NEON OR NOT HAVE_AVX2) AND (${nof_prb} EQUAL 100))
continue()
endif ()
foreach (nof_ports 1 2)

View File

@ -251,7 +251,7 @@ void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n
}
// Bytes needed for tx SDUs
if (tx_window.size() < 1024) {
if (not window_full()) {
n_sdus = tx_sdu_queue.get_n_sdus();
n_bytes_newtx += tx_sdu_queue.size_bytes();
if (tx_sdu != NULL) {
@ -299,7 +299,7 @@ uint32_t rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
}
// Section 5.2.2.3 in TS 36.311, if tx_window is full and retx_queue empty, retransmit PDU
if (tx_window.size() >= RLC_AM_WINDOW_SIZE && retx_queue.empty()) {
if (window_full() && retx_queue.empty()) {
retransmit_pdu(vt_a);
}
@ -323,7 +323,7 @@ void rlc_am_lte_tx::timer_expired(uint32_t timeout_id)
// Section 5.2.2.3 in TS 36.322, schedule PDU for retransmission if
// (a) both tx and retx buffer are empty (excluding tx'ed PDU waiting for ack), or
// (b) no new data PDU can be transmitted (tx window is full)
if ((retx_queue.empty() && tx_sdu_queue.size() == 0) || tx_window.size() >= RLC_AM_WINDOW_SIZE) {
if ((retx_queue.empty() && tx_sdu_queue.size() == 0) || window_full()) {
retransmit_pdu(vt_a); // TODO: TS says to send vt_s - 1 here
}
} else if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) {
@ -368,6 +368,11 @@ void rlc_am_lte_tx::retransmit_pdu(uint32_t sn)
* Helper functions
***************************************************************************/
bool rlc_am_lte_tx::window_full()
{
return TX_MOD_BASE(vt_s) >= RLC_AM_WINDOW_SIZE;
};
/**
* Called when building a RLC PDU for checking whether the poll bit needs
* to be set.
@ -394,7 +399,7 @@ bool rlc_am_lte_tx::poll_required()
return true;
}
if (tx_window.size() >= RLC_AM_WINDOW_SIZE) {
if (window_full()) {
RlcDebug("Poll required. Cause: TX window full.");
return true;
}
@ -699,7 +704,7 @@ int rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes)
}
// do not build any more PDU if window is already full
if (tx_window.size() >= RLC_AM_WINDOW_SIZE) {
if (window_full()) {
RlcInfo("Cannot build data PDU - Tx window full.");
return 0;
}
@ -1165,7 +1170,8 @@ rlc_am_lte_rx::rlc_am_lte_rx(rlc_am* parent_) :
pool(byte_buffer_pool::get_instance()),
reordering_timer(parent_->timers->get_unique_timer()),
rlc_am_base_rx(parent_, parent_->logger)
{}
{
}
bool rlc_am_lte_rx::configure(const rlc_config_t& cfg_)
{

View File

@ -3766,6 +3766,322 @@ bool poll_retx_expiry_test()
return SRSRAN_SUCCESS;
}
bool full_window_check_test()
{
rlc_config_t config = rlc_config_t::default_rlc_am_config();
// [I] SRB1 configured: t_poll_retx=65, poll_pdu=-1, poll_byte=-1, max_retx_thresh=6, t_reordering=55,
// t_status_prohibit=0
config.am.t_poll_retx = 65;
config.am.poll_pdu = -1;
config.am.poll_byte = -1;
config.am.max_retx_thresh = 6;
config.am.t_reordering = 55;
config.am.t_status_prohibit = 55;
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_poll_rext_expiry_test.pcap", config);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100);
srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100);
srslog::fetch_basic_logger("RLC").set_hex_dump_max_size(100);
if (not rlc1.configure(config)) {
return -1;
}
if (not rlc2.configure(config)) {
return -1;
}
{
// Initial Tx
uint32_t num_tx_pdus = 512;
for (uint32_t i = 0; i < num_tx_pdus; ++i) {
// Write SDU
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
TESTASSERT(sdu != nullptr);
sdu->N_bytes = 1;
sdu->msg[0] = i;
sdu->md.pdcp_sn = i;
rlc1.write_sdu(std::move(sdu));
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = 1;
pdu->msg[0] = i;
pdu->md.pdcp_sn = i;
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
}
}
{
// Tx one more to check the window is full
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
TESTASSERT(sdu != nullptr);
sdu->N_bytes = 1;
sdu->msg[0] = 0;
sdu->md.pdcp_sn = 512;
rlc1.write_sdu(std::move(sdu));
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
// If the TX window is full, we should RETX SN=0
rlc_amd_pdu_header_t header = {};
rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header);
TESTASSERT_EQ(header.sn, 0);
TESTASSERT_EQ(header.N_li, 0);
TESTASSERT_EQ(header.fi, 0);
}
// Ack one SN in the middle of the TX window.
// This is done to make sure the full window check is correct
// even if PDUs in the middle of the window are ACKed.
// ACK_SN=3, NACK_SN=0
{
rlc_status_pdu_t status = {};
status.ack_sn = 3;
status.N_nack = 1;
status.nacks[0].nack_sn = 0;
unique_byte_buffer_t status_buf = srsran::make_byte_buffer();
TESTASSERT(status_buf != nullptr);
rlc_am_write_status_pdu(&status, status_buf.get());
rlc1.write_pdu(status_buf->msg, status_buf->N_bytes);
// Read RETX for SN=0 from NACK
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
// Check RETX SN=0
rlc_amd_pdu_header_t header = {};
rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header);
TESTASSERT_EQ(header.sn, 0);
TESTASSERT_EQ(header.N_li, 0);
TESTASSERT_EQ(header.fi, 0);
TESTASSERT_EQ(0, rlc1.get_buffer_state());
}
{
// Tx more PDUs to check the window is still full
uint32_t num_tx_pdus = 2;
for (uint32_t i = 0; i < num_tx_pdus; ++i) {
// Write SDU
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
TESTASSERT(sdu != nullptr);
sdu->N_bytes = 1;
sdu->msg[0] = i;
sdu->md.pdcp_sn = i;
rlc1.write_sdu(std::move(sdu));
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = 1;
pdu->msg[0] = i;
pdu->md.pdcp_sn = i;
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
// If the TX window is full, we should RETX SN=0
rlc_amd_pdu_header_t header = {};
rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header);
TESTASSERT_EQ(header.sn, 0);
TESTASSERT_EQ(header.N_li, 0);
TESTASSERT_EQ(header.fi, 0);
}
}
// ACK more PDUs and advance VT(A).
// New PDUs should be available to read now.
{
rlc_status_pdu_t status = {};
status.ack_sn = 5;
status.N_nack = 0;
unique_byte_buffer_t status_buf = srsran::make_byte_buffer();
TESTASSERT(status_buf != nullptr);
rlc_am_write_status_pdu(&status, status_buf.get());
rlc1.write_pdu(status_buf->msg, status_buf->N_bytes);
// Read new PDU
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
// If the TX window is no longer full, we should TX a new SN (SN=512)
rlc_amd_pdu_header_t header = {};
rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header);
TESTASSERT_EQ(header.sn, 512);
TESTASSERT_EQ(header.N_li, 0);
TESTASSERT_EQ(header.fi, 0);
}
#if HAVE_PCAP
pcap.close();
#endif
return SRSRAN_SUCCESS;
}
bool full_window_check_wraparound_test()
{
rlc_config_t config = rlc_config_t::default_rlc_am_config();
// [I] SRB1 configured: t_poll_retx=65, poll_pdu=-1, poll_byte=-1, max_retx_thresh=6, t_reordering=55,
// t_status_prohibit=0
config.am.t_poll_retx = 65;
config.am.poll_pdu = -1;
config.am.poll_byte = -1;
config.am.max_retx_thresh = 6;
config.am.t_reordering = 55;
config.am.t_status_prohibit = 55;
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_poll_rext_expiry_test.pcap", config);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(true, NULL);
#endif
uint32_t pdcp_count = 0;
srsran::timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100);
srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100);
srslog::fetch_basic_logger("RLC").set_hex_dump_max_size(100);
if (not rlc1.configure(config)) {
return -1;
}
if (not rlc2.configure(config)) {
return -1;
}
// Advance vt_a to 512 and vt_s to 512 as well.
{
// Initial Tx
uint32_t num_tx_pdus = 512;
for (uint32_t i = 0; i < num_tx_pdus; ++i) {
// Write SDU
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
TESTASSERT(sdu != nullptr);
sdu->N_bytes = 1;
sdu->msg[0] = i;
sdu->md.pdcp_sn = pdcp_count++;
rlc1.write_sdu(std::move(sdu));
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
}
// ACK all SNs to advance the TX window.
rlc_status_pdu_t status = {};
status.ack_sn = num_tx_pdus;
status.N_nack = 0;
unique_byte_buffer_t status_buf = srsran::make_byte_buffer();
TESTASSERT(status_buf != nullptr);
rlc_am_write_status_pdu(&status, status_buf.get());
rlc1.write_pdu(status_buf->msg, status_buf->N_bytes);
}
// Advance vt_a and vt_s to 1023
{
// Initial Tx
uint32_t num_tx_pdus = 511;
for (uint32_t i = 0; i < num_tx_pdus; ++i) {
// Write SDU
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
TESTASSERT(sdu != nullptr);
sdu->N_bytes = 1;
sdu->msg[0] = i;
sdu->md.pdcp_sn = pdcp_count++;
rlc1.write_sdu(std::move(sdu));
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
}
// ACK all SNs to advance the TX window.
rlc_status_pdu_t status = {};
status.ack_sn = 512 + num_tx_pdus;
status.N_nack = 0;
unique_byte_buffer_t status_buf = srsran::make_byte_buffer();
TESTASSERT(status_buf != nullptr);
rlc_am_write_status_pdu(&status, status_buf.get());
rlc1.write_pdu(status_buf->msg, status_buf->N_bytes);
}
// Now, fill up the window
{
// Initial Tx
uint32_t num_tx_pdus = 512;
for (uint32_t i = 0; i < num_tx_pdus; ++i) {
// Write SDU
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
TESTASSERT(sdu != nullptr);
sdu->N_bytes = 1;
sdu->msg[0] = i;
sdu->md.pdcp_sn = pdcp_count++;
rlc1.write_sdu(std::move(sdu));
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
}
}
{
// Tx one more to check the window is full
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
TESTASSERT(sdu != nullptr);
sdu->N_bytes = 1;
sdu->msg[0] = 0;
sdu->md.pdcp_sn = pdcp_count++;
rlc1.write_sdu(std::move(sdu));
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
TESTASSERT(pdu != nullptr);
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
TESTASSERT(pdu->N_bytes == 3);
// If the TX window is full, we should RETX SN=1023
rlc_amd_pdu_header_t header = {};
rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header);
TESTASSERT_EQ(header.sn, 1023);
TESTASSERT_EQ(header.N_li, 0);
TESTASSERT_EQ(header.fi, 0);
}
#if HAVE_PCAP
pcap.close();
#endif
return SRSRAN_SUCCESS;
}
int main(int argc, char** argv)
{
// Setup the log message spy to intercept error and warning log entries from RLC
@ -3975,5 +4291,15 @@ int main(int argc, char** argv)
printf("poll_retx_expiry_test failed\n");
exit(-1);
};
if (full_window_check_test()) {
printf("full_window_check_test failed\n");
exit(-1);
};
if (full_window_check_wraparound_test()) {
printf("full_window_check_wraparound_test failed\n");
exit(-1);
};
return SRSRAN_SUCCESS;
}

View File

@ -137,12 +137,65 @@ sib3 =
}
};
#####################################################################
# sib6 configuration options (See TS 36.331)
# Contains UTRA neighbor information for inter-rat handover.
# Must be added to sib1::sched_info::si_mapping_info array parameter to be transmitted
#
# t_resel_utra: Cell reselection timer (seconds)
# t_resel_utra_sf: Optional speed dependent ScalingFactor for t_resel_utra.
# sf_medium: Scaling factor if the UE is in Medium Mobility state, one of "0.25", "0.5", "0.75" or "1.0".
# sf_high: Scaling factor if the UE is in High Mobility state, one of "0.25", "0.5", "0.75" or "1.0".
# carrier_freq_list_utra_fdd / carrier_freq_list_utra_tdd: A list of carrier frequencies of UTRA FDD / TDD.
# carrier_freq: The UARFCN for the UTRA carrier frequency.
# cell_resel_prio: Optional absolute priority of the carrier frequency group.
# thresh_x_high: Srclev threshold (dB) to select to a higher-priority RAT/Frequency.
# thresh_x_low: Srclev threshold (dB) to select to a lower-priority RAT/Frequency.
# q_rx_lev_min: Minimum receive level in UTRA cell, ([field_val] * 2) + 1 = [level in dBm].
# p_max_utra: The maximum allowed transmission power on the (uplink) carrier frequency.
# q_qual_min: Minimum required quality leve in UTRA cell, applicable only for FDD cells.
#
#####################################################################
sib6 =
{
t_resel_utra = 1;
t_resel_utra_sf = {
sf_medium = "0.25";
sf_high = "1.0";
}
carrier_freq_list_utra_fdd =
(
{
carrier_freq = 9613;
cell_resel_prio = 6;
thresh_x_high = 3;
thresh_x_low = 2;
q_rx_lev_min = -50;
p_max_utra = 4;
q_qual_min = -10;
}
);
carrier_freq_list_utra_tdd =
(
{
carrier_freq = 9505;
thresh_x_high = 1;
thresh_x_low = 2;
q_rx_lev_min = -50;
p_max_utra = -3;
}
);
};
#####################################################################
# sib7 configuration options (See TS 36.331)
# Contains GERAN neighbor information for CSFB and inter-rat handover.
# Must be added to sib1::sched_info::si_mapping_info array parameter to be transmitted
#
# t_resel_geran: Cell reselection timer (seconds)
# t_resel_geran_sf: Optional speed dependent ScalingFactor for t_resel_geran.
# sf_medium: Scaling factor if the UE is in Medium Mobility state, one of "0.25", "0.5", "0.75" or "1.0".
# sf_high: Scaling factor if the UE is in High Mobility state, one of "0.25", "0.5", "0.75" or "1.0".
# carrier_freqs_info_list: A list of carrier frequency groups.
# cell_resel_prio: Absolute priority of the carrier frequency group
# ncc_permitted: 8-bit bitmap of NCC carriers permitted for monitoring

View File

@ -133,7 +133,7 @@ int field_intra_neigh_cell_list::parse(libconfig::Setting& root)
int field_intra_black_cell_list::parse(libconfig::Setting& root)
{
data->intra_freq_black_cell_list.resize((uint32_t)root.getLength());
data->intra_freq_black_cell_list_present = data->intra_freq_neigh_cell_list.size() > 0;
data->intra_freq_black_cell_list_present = data->intra_freq_black_cell_list.size() > 0;
for (uint32_t i = 0; i < data->intra_freq_black_cell_list.size() && i < ASN1_RRC_MAX_CELL_BLACK; i++) {
if (not parse_enum_by_number(data->intra_freq_black_cell_list[i].range, "range", root[i])) {
fprintf(stderr, "Missing field range in black_cell=%d\n", i);
@ -151,6 +151,111 @@ int field_intra_black_cell_list::parse(libconfig::Setting& root)
return 0;
}
int field_carrier_freq_list_utra_fdd::parse(libconfig::Setting& root)
{
data->carrier_freq_list_utra_fdd.resize((uint32_t)root.getLength());
data->carrier_freq_list_utra_fdd_present = data->carrier_freq_list_utra_fdd.size() > 0;
for (uint32_t i = 0; i < data->carrier_freq_list_utra_fdd.size() && i < ASN1_RRC_MAX_UTRA_FDD_CARRIER; i++) {
unsigned int carrier_freq = 0;
if (!root[i].lookupValue("carrier_freq", carrier_freq)) {
fprintf(stderr, "Missing field `carrier_freq` in carrier_freq_list_utra_fdd=%d\n", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_fdd[i].carrier_freq = carrier_freq;
unsigned int cell_resel_prio = 0;
if (root[i].lookupValue("cell_resel_prio", cell_resel_prio)) {
data->carrier_freq_list_utra_fdd[i].cell_resel_prio_present = true;
data->carrier_freq_list_utra_fdd[i].cell_resel_prio = cell_resel_prio;
}
unsigned int thresh_x_high = 0;
if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) {
ERROR("Missing field `thresh_x_high` in carrier_freq_list_utra_fdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_fdd[i].thresh_x_high = thresh_x_high;
unsigned int thresh_x_low = 0;
if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) {
ERROR("Missing field `thresh_x_low` in carrier_freq_list_utra_fdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_fdd[i].thresh_x_low = thresh_x_low;
int q_rx_lev_min = 0;
if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) {
ERROR("Missing field `q_rx_lev_min` in carrier_freq_list_utra_fdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_fdd[i].q_rx_lev_min = q_rx_lev_min;
int p_max_utra = 0;
if (!root[i].lookupValue("p_max_utra", p_max_utra)) {
ERROR("Missing field `p_max_utra` in carrier_freq_list_utra_fdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_fdd[i].p_max_utra = p_max_utra;
int q_qual_min = 0;
if (!root[i].lookupValue("q_qual_min", q_qual_min)) {
ERROR("Missing field `q_qual_min` in carrier_freq_list_utra_fdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_fdd[i].q_qual_min = q_qual_min;
}
return 0;
}
int field_carrier_freq_list_utra_tdd::parse(libconfig::Setting& root)
{
data->carrier_freq_list_utra_tdd.resize((uint32_t)root.getLength());
data->carrier_freq_list_utra_tdd_present = data->carrier_freq_list_utra_tdd.size() > 0;
for (uint32_t i = 0; i < data->carrier_freq_list_utra_tdd.size() && i < ASN1_RRC_MAX_UTRA_TDD_CARRIER; i++) {
unsigned int carrier_freq = 0;
if (!root[i].lookupValue("carrier_freq", carrier_freq)) {
fprintf(stderr, "Missing field `carrier_freq` in carrier_freq_list_utra_tdd=%d\n", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_tdd[i].carrier_freq = carrier_freq;
unsigned int cell_resel_prio = 0;
if (root[i].lookupValue("cell_resel_prio", cell_resel_prio)) {
data->carrier_freq_list_utra_tdd[i].cell_resel_prio_present = true;
data->carrier_freq_list_utra_tdd[i].cell_resel_prio = cell_resel_prio;
}
unsigned int thresh_x_high = 0;
if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) {
ERROR("Missing field `thresh_x_high` in carrier_freq_list_utra_tdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_tdd[i].thresh_x_high = thresh_x_high;
unsigned int thresh_x_low = 0;
if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) {
ERROR("Missing field `thresh_x_low` in carrier_freq_list_utra_tdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_tdd[i].thresh_x_low = thresh_x_low;
int q_rx_lev_min = 0;
if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) {
ERROR("Missing field `q_rx_lev_min` in carrier_freq_list_utra_tdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_tdd[i].q_rx_lev_min = q_rx_lev_min;
int p_max_utra = 0;
if (!root[i].lookupValue("p_max_utra", p_max_utra)) {
ERROR("Missing field `p_max_utra` in carrier_freq_list_utra_tdd=%d", i);
return SRSRAN_ERROR;
}
data->carrier_freq_list_utra_tdd[i].p_max_utra = p_max_utra;
}
return 0;
}
int field_carrier_freqs_info_list::parse(libconfig::Setting& root)
{
data->carrier_freqs_info_list.resize((uint32_t)root.getLength());
@ -175,7 +280,7 @@ int field_carrier_freqs_info_list::parse(libconfig::Setting& root)
field_asn1_bitstring_number<asn1::fixed_bitstring<8>, uint8_t> ncc_permitted(
"ncc_permitted", &data->carrier_freqs_info_list[i].common_info.ncc_permitted);
if (ncc_permitted.parse(root[i])) {
ERROR("Error parsing `ncc_permitted` in carrier_freqs_info_lsit=%d", i);
ERROR("Error parsing `ncc_permitted` in carrier_freqs_info_list=%d", i);
return SRSRAN_ERROR;
}
@ -2003,7 +2108,7 @@ int parse_sib2(std::string filename, sib_type2_s* data)
acbarring_data.add_field(
make_asn1_enum_number_str_parser("factor", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_factor));
acbarring_data.add_field(make_asn1_enum_number_parser("fime", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_time));
acbarring_data.add_field(make_asn1_enum_number_parser("time", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_time));
acbarring_data.add_field(make_asn1_bitstring_number_parser(
"for_special_ac", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_for_special_ac));
@ -2240,12 +2345,48 @@ int parse_sib4(std::string filename, sib_type4_s* data)
return parser::parse_section(std::move(filename), &sib4);
}
int parse_sib6(std::string filename, sib_type6_s* data)
{
parser::section sib6("sib6");
// t-ReselectionUTRA
sib6.add_field(new parser::field<uint8>("t_resel_utra", &data->t_resel_utra));
// t-ReselectionUTRA-SF
parser::section t_resel_utra_sf("t_resel_utra_sf");
sib6.add_subsection(&t_resel_utra_sf);
t_resel_utra_sf.set_optional(&data->t_resel_utra_sf_present);
t_resel_utra_sf.add_field(make_asn1_enum_number_str_parser("sf_medium", &data->t_resel_utra_sf.sf_medium));
t_resel_utra_sf.add_field(make_asn1_enum_number_str_parser("sf_high", &data->t_resel_utra_sf.sf_high));
// carrierFreqListUTRA-FDD
parser::section carrier_freq_list_utra_fdd("carrier_freq_list_utra_fdd");
sib6.add_subsection(&carrier_freq_list_utra_fdd);
bool dummy_bool = false;
carrier_freq_list_utra_fdd.set_optional(&dummy_bool);
carrier_freq_list_utra_fdd.add_field(new field_carrier_freq_list_utra_fdd(data));
// carrierFreqListUTRA-TDD
parser::section carrier_freq_list_utra_tdd("carrier_freq_list_utra_tdd");
sib6.add_subsection(&carrier_freq_list_utra_tdd);
carrier_freq_list_utra_tdd.set_optional(&dummy_bool);
carrier_freq_list_utra_tdd.add_field(new field_carrier_freq_list_utra_tdd(data));
return parser::parse_section(std::move(filename), &sib6);
}
int parse_sib7(std::string filename, sib_type7_s* data)
{
parser::section sib7("sib7");
sib7.add_field(new parser::field<uint8>("t_resel_geran", &data->t_resel_geran));
// TODO: t_resel_geran_sf
parser::section t_resel_geran_sf("t_resel_geran_sf");
sib7.add_subsection(&t_resel_geran_sf);
t_resel_geran_sf.set_optional(&data->t_resel_geran_sf_present);
t_resel_geran_sf.add_field(make_asn1_enum_number_str_parser("sf_medium", &data->t_resel_geran_sf.sf_medium));
t_resel_geran_sf.add_field(make_asn1_enum_number_str_parser("sf_high", &data->t_resel_geran_sf.sf_high));
data->carrier_freqs_info_list_present = true;
parser::section geran_neigh("carrier_freqs_info_list");
@ -2317,6 +2458,7 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
sib_type2_s* sib2 = &rrc_cfg_->sibs[1].set_sib2();
sib_type3_s* sib3 = &rrc_cfg_->sibs[2].set_sib3();
sib_type4_s* sib4 = &rrc_cfg_->sibs[3].set_sib4();
sib_type6_s* sib6 = &rrc_cfg_->sibs[5].set_sib6();
sib_type7_s* sib7 = &rrc_cfg_->sibs[6].set_sib7();
sib_type9_s* sib9 = &rrc_cfg_->sibs[8].set_sib9();
sib_type13_r9_s* sib13 = &rrc_cfg_->sibs[12].set_sib13_v920();
@ -2386,6 +2528,13 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
}
}
// Generate SIB6 if defined in mapping info
if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type6)) {
if (sib_sections::parse_sib6(args_->enb_files.sib_config, sib6) != SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
}
// Generate SIB7 if defined in mapping info
if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type7)) {
if (sib_sections::parse_sib7(args_->enb_files.sib_config, sib7) != SRSRAN_SUCCESS) {

View File

@ -63,6 +63,7 @@ int parse_sib1(std::string filename, asn1::rrc::sib_type1_s* data);
int parse_sib2(std::string filename, asn1::rrc::sib_type2_s* data);
int parse_sib3(std::string filename, asn1::rrc::sib_type3_s* data);
int parse_sib4(std::string filename, asn1::rrc::sib_type4_s* data);
int parse_sib6(std::string filename, asn1::rrc::sib_type6_s* data);
int parse_sib7(std::string filename, asn1::rrc::sib_type7_s* data);
int parse_sib9(std::string filename, asn1::rrc::sib_type9_s* data);
int parse_sib13(std::string filename, asn1::rrc::sib_type13_r9_s* data);
@ -149,6 +150,28 @@ private:
asn1::rrc::sib_type4_s* data;
};
class field_carrier_freq_list_utra_fdd final : public parser::field_itf
{
public:
explicit field_carrier_freq_list_utra_fdd(asn1::rrc::sib_type6_s* data_) { data = data_; }
int parse(Setting& root) override;
const char* get_name() override { return "carrier_freq_list_utra_fdd"; }
private:
asn1::rrc::sib_type6_s* data;
};
class field_carrier_freq_list_utra_tdd final : public parser::field_itf
{
public:
explicit field_carrier_freq_list_utra_tdd(asn1::rrc::sib_type6_s* data_) { data = data_; }
int parse(Setting& root) override;
const char* get_name() override { return "carrier_freq_list_utra_tdd"; }
private:
asn1::rrc::sib_type6_s* data;
};
class field_carrier_freqs_info_list final : public parser::field_itf
{
public:

View File

@ -358,7 +358,9 @@ void phy::configure_mbsfn(srsran::sib2_mbms_t* sib2, srsran::sib13_t* sib13, con
// Start GUI
void phy::start_plot()
{
lte_workers[0]->start_plot();
if (lte_workers.get_nof_workers() > 0) {
lte_workers[0]->start_plot();
}
}
int phy::init_nr(const phy_args_t& args, const phy_cfg_t& cfg, stack_interface_phy_nr& stack)

View File

@ -21,6 +21,7 @@
# (supported: EIA0 (rejected by most UEs), EIA1 (default), EIA2, EIA3
# paging_timer: Value of paging timer in seconds (T3413)
# request_imeisv: Request UE's IMEI-SV in security mode command
# lac: 16-bit Location Area Code.
#
#####################################################################
[mme]
@ -36,6 +37,7 @@ encryption_algo = EEA0
integrity_algo = EIA1
paging_timer = 2
request_imeisv = false
lac = 0x0006
#####################################################################
# HSS configuration

View File

@ -142,6 +142,7 @@ typedef struct {
srsran::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
srsran::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
bool request_imeisv;
uint16_t lac;
} nas_init_t;
typedef struct {
@ -280,6 +281,7 @@ private:
std::string m_full_net_name;
std::string m_short_net_name;
bool m_request_imeisv = false;
uint16_t m_lac = 0;
// Timers timeout values
uint16_t m_t3413 = 0;

View File

@ -52,6 +52,7 @@ typedef struct {
srsran::CIPHERING_ALGORITHM_ID_ENUM encryption_algo;
srsran::INTEGRITY_ALGORITHM_ID_ENUM integrity_algo;
bool request_imeisv;
uint16_t lac;
} s1ap_args_t;
typedef struct {

View File

@ -97,6 +97,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
string hss_db_file;
string hss_auth_algo;
string log_filename;
string lac;
// Command line only options
bpo::options_description general("General options");
@ -124,6 +125,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("mme.integrity_algo", bpo::value<string>(&integrity_algo)->default_value("EIA1"), "Set preferred integrity protection algorithm for NAS")
("mme.paging_timer", bpo::value<uint16_t>(&paging_timer)->default_value(2), "Set paging timer value in seconds (T3413)")
("mme.request_imeisv", bpo::value<bool>(&request_imeisv)->default_value(false), "Enable IMEISV request in Security mode command")
("mme.lac", bpo::value<string>(&lac)->default_value("0x01"), "Location Area Code")
("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"), ".csv file that stores UE's keys")
("spgw.gtpu_bind_addr", bpo::value<string>(&spgw_bind_addr)->default_value("127.0.0.1"), "IP address of SP-GW for the S1-U connection")
("spgw.sgi_if_addr", bpo::value<string>(&sgi_if_addr)->default_value("176.16.0.1"), "IP address of TUN interface for the SGi connection")
@ -227,6 +229,11 @@ void parse_args(all_args_t* args, int argc, char* argv[])
sstr << std::hex << vm["mme.tac"].as<std::string>();
sstr >> args->mme_args.s1ap_args.tac;
}
{
std::stringstream sstr;
sstr << std::hex << vm["mme.lac"].as<std::string>();
sstr >> args->mme_args.s1ap_args.lac;
}
// Convert MCC/MNC strings
if (!srsran::string_to_mcc(mcc, &args->mme_args.s1ap_args.mcc)) {

View File

@ -46,7 +46,8 @@ nas::nas(const nas_init_t& args, const nas_if_t& itf) :
m_full_net_name(args.full_net_name),
m_short_net_name(args.short_net_name),
m_t3413(args.paging_timer),
m_request_imeisv(args.request_imeisv)
m_request_imeisv(args.request_imeisv),
m_lac(args.lac)
{
m_sec_ctx.integ_algo = args.integ_algo;
m_sec_ctx.cipher_algo = args.cipher_algo;
@ -1550,7 +1551,7 @@ bool nas::pack_attach_accept(srsran::byte_buffer_t* nas_buffer)
attach_accept.lai_present = true;
attach_accept.lai.mcc = mcc;
attach_accept.lai.mnc = mnc;
attach_accept.lai.lac = 001;
attach_accept.lai.lac = m_lac;
attach_accept.ms_id_present = true;
attach_accept.ms_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_TMSI;

View File

@ -81,6 +81,7 @@ void s1ap_nas_transport::init()
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;
m_nas_init.lac = m_s1ap->m_s1ap_args.lac;
// Init NAS interface
m_nas_if.s1ap = s1ap::get_instance();

View File

@ -26,7 +26,7 @@ sudo -v || exit
#Check if outbound interface was specified
if [ ! $# -eq 1 ]
then
echo "Usage :'sudo ./if_masq.sh <Interface Name>' "
echo "Usage :'sudo ./srsepc_if_masq.sh <Interface Name>' "
exit
fi

View File

@ -224,6 +224,7 @@ private:
srslog::basic_logger& rrc_logger;
srslog::basic_logger& usim_logger;
srslog::basic_logger& nas_logger;
srslog::basic_logger& nas5g_logger;
// UE NR stack logging
srslog::basic_logger& mac_nr_logger;

View File

@ -42,6 +42,7 @@ ue_stack_lte::ue_stack_lte() :
rrc_logger(srslog::fetch_basic_logger("RRC", false)),
usim_logger(srslog::fetch_basic_logger("USIM", false)),
nas_logger(srslog::fetch_basic_logger("NAS", false)),
nas5g_logger(srslog::fetch_basic_logger("NAS5G", false)),
mac_nr_logger(srslog::fetch_basic_logger("MAC-NR")),
rrc_nr_logger(srslog::fetch_basic_logger("RRC-NR", false)),
rlc_nr_logger(srslog::fetch_basic_logger("RLC-NR", false)),
@ -128,6 +129,8 @@ int ue_stack_lte::init(const stack_args_t& args_)
nas_logger.set_level(srslog::str_to_basic_level(args.log.nas_level));
nas_logger.set_hex_dump_max_size(args.log.nas_hex_limit);
nas5g_logger.set_level(srslog::str_to_basic_level(args.log.nas_level));
nas5g_logger.set_hex_dump_max_size(args.log.nas_hex_limit);
mac_nr_logger.set_level(srslog::str_to_basic_level(args.log.mac_level));
mac_nr_logger.set_hex_dump_max_size(args.log.mac_hex_limit);
rrc_nr_logger.set_level(srslog::str_to_basic_level(args.log.rrc_level));
@ -201,6 +204,7 @@ int ue_stack_lte::init(const stack_args_t& args_)
if (args.pkt_trace.nas_pcap.enable) {
if (nas_pcap.open(args.pkt_trace.nas_pcap.filename.c_str()) == SRSRAN_SUCCESS) {
nas.start_pcap(&nas_pcap);
nas_5g.start_pcap(&nas_pcap);
stack_logger.info("Open nas pcap file %s", args.pkt_trace.nas_pcap.filename.c_str());
} else {
stack_logger.error("Can not open pcap file %s", args.pkt_trace.nas_pcap.filename.c_str());