Merge branch 'next'

master
Andre Puschmann 5 years ago
commit 6d62e15d2a

@ -3,10 +3,30 @@ sudo: required
before_script:
- sudo apt-get -qq update
- sudo apt-get install -qq build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev
- sudo apt-get install -qq build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff
language: cpp
addons:
apt:
sources:
- llvm-toolchain-trusty-8
- key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- clang-format-8
script:
- sudo ln -s /usr/bin/clang-format-diff-8 /usr/bin/clang-format-diff
- git remote set-branches --add origin master
- git fetch
- |
if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then
# Run only for PRs because target branch is needed to do the clang-format check
echo "Checking clang-format between TRAVIS_BRANCH=$TRAVIS_BRANCH and TRAVIS_PULL_REQUEST_BRANCH=$TRAVIS_PULL_REQUEST_BRANCH"
./run-clang-format-diff.sh "$TRAVIS_BRANCH" "$TRAVIS_PULL_REQUEST_BRANCH"
else
echo "Skipping clang-format check"
fi
- mkdir build
- cd build
- cmake -DRF_FOUND=True ..

@ -1,6 +1,17 @@
Change Log for Releases
==============================
## 19.09
* Add initial support for NR in MAC/RLC/PDCP
* Add sync code for NB-IoT
* Add support for EIA3/EEA3 (i.e. ZUC)
* Add support for CSFB in srsENB
* Add adaptation layer to run TTCN-3 conformance tests for srsUE
* Add High Speed Train model to channel simulator
* Rework RRC and NAS layer and make them non-blocking
* Fixes in ZMQ, bladeRF and Soapy RF modules
* Other bug-fixes and improved stability and performance in all parts
## 19.06
* Add QAM256 support in srsUE
* Add QoS support in srsUE

@ -55,7 +55,7 @@ set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
# Generate CMake to include build information
configure_file(
${CMAKE_SOURCE_DIR}/cmake/modules/SRSLTEbuildinfo.cmake.in
${PROJECT_SOURCE_DIR}/cmake/modules/SRSLTEbuildinfo.cmake.in
${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake
)
@ -74,6 +74,8 @@ option(ENABLE_SOAPYSDR "Enable SoapySDR" ON)
option(ENABLE_ZEROMQ "Enable ZeroMQ" ON)
option(ENABLE_HARDSIM "Enable support for SIM cards" ON)
option(ENABLE_TTCN3 "Enable TTCN3 test binaries" OFF)
option(BUILD_STATIC "Attempt to statically link external deps" OFF)
option(RPATH "Enable RPATH" OFF)
option(ENABLE_ASAN "Enable gcc/clang address sanitizer" OFF)
@ -194,28 +196,33 @@ else(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR ZEROMQ_FOUND)
endif(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR ZEROMQ_FOUND)
# Boost
if(ENABLE_SRSUE OR ENABLE_SRSENB OR ENABLE_SRSEPC)
if(BUILD_STATIC)
set(Boost_USE_STATIC_LIBS ON)
endif(BUILD_STATIC)
if(BUILD_STATIC)
set(Boost_USE_STATIC_LIBS ON)
endif(BUILD_STATIC)
set(BOOST_REQUIRED_COMPONENTS
program_options
)
if(UNIX AND EXISTS "/usr/lib64")
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
endif(UNIX AND EXISTS "/usr/lib64")
set(Boost_ADDITIONAL_VERSIONS
"1.35.0" "1.35" "1.36.0" "1.36" "1.37.0" "1.37" "1.38.0" "1.38" "1.39.0" "1.39"
"1.40.0" "1.40" "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44"
"1.45.0" "1.45" "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.49.0" "1.49"
"1.50.0" "1.50" "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54"
"1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59"
"1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64"
"1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69"
)
find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
endif(ENABLE_SRSUE OR ENABLE_SRSENB OR ENABLE_SRSEPC)
set(BOOST_REQUIRED_COMPONENTS
program_options
)
if(UNIX AND EXISTS "/usr/lib64")
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
endif(UNIX AND EXISTS "/usr/lib64")
set(Boost_ADDITIONAL_VERSIONS
"1.35.0" "1.35" "1.36.0" "1.36" "1.37.0" "1.37" "1.38.0" "1.38" "1.39.0" "1.39"
"1.40.0" "1.40" "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44"
"1.45.0" "1.45" "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.49.0" "1.49"
"1.50.0" "1.50" "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54"
"1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59"
"1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64"
"1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69"
)
find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
else(Boost_FOUND)
message(FATAL_ERROR "Boost required to build srsLTE")
endif (Boost_FOUND)
# srsGUI
if(ENABLE_GUI)
@ -227,6 +234,14 @@ if(ENABLE_GUI)
endif(SRSGUI_FOUND)
endif(ENABLE_GUI)
if (ENABLE_TTCN3)
find_package(RapidJSON REQUIRED)
add_definitions(-DENABLE_TTCN3)
include_directories(${RAPIDJSON_INCLUDE_DIRS})
link_directories(${RAPIDJSON_LIBRARY_DIRS})
message(STATUS "Building with TTCN3 binaries")
endif (ENABLE_TTCN3)
########################################################################
# Install Dirs
########################################################################
@ -248,7 +263,7 @@ set(DATA_DIR share/${CPACK_PACKAGE_NAME})
# Auto-generate config install helper and mark for installation
configure_file(
${CMAKE_SOURCE_DIR}/cmake/modules/SRSLTE_install_configs.sh.in
${PROJECT_SOURCE_DIR}/cmake/modules/SRSLTE_install_configs.sh.in
${CMAKE_BINARY_DIR}/srslte_install_configs.sh
)
install(PROGRAMS ${CMAKE_BINARY_DIR}/srslte_install_configs.sh DESTINATION ${RUNTIME_DIR})
@ -372,6 +387,13 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup")
endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Add -Werror to C/C++ flags for newer compilers
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
message(STATUS "CMAKE_C_FLAGS is ${CMAKE_C_FLAGS}")
message(STATUS "CMAKE_CXX_FLAGS is ${CMAKE_CXX_FLAGS}")

@ -14,31 +14,37 @@
FIND_PATH(LIBCONFIG_INCLUDE_DIR libconfig.h
/usr/local/include
/usr/include
/usr/lib/x86_64-linux-gnu/
)
FIND_PATH(LIBCONFIGPP_INCLUDE_DIR libconfig.h++
/usr/local/include
/usr/include
/usr/lib/x86_64-linux-gnu/
)
FIND_LIBRARY(LIBCONFIG_LIBRARY config
/usr/local/lib
/usr/lib
/usr/lib/x86_64-linux-gnu/
)
FIND_LIBRARY(LIBCONFIGPP_LIBRARY config++
/usr/local/lib
/usr/lib
/usr/lib/x86_64-linux-gnu/
)
FIND_LIBRARY(LIBCONFIG_STATIC_LIBRARY "libconfig${CMAKE_STATIC_LIBRARY_SUFFIX}"
/usr/local/lib
/usr/lib
/usr/lib/x86_64-linux-gnu/
)
FIND_LIBRARY(LIBCONFIGPP_STATIC_LIBRARY "libconfig++${CMAKE_STATIC_LIBRARY_SUFFIX}"
/usr/local/lib
/usr/lib
/usr/local/lib
/usr/lib
/usr/lib/x86_64-linux-gnu/
)

@ -0,0 +1,97 @@
# Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
# Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com)
# Distributed under the MIT License (see license.txt file)
# -----------------------------------------------------------------------------------
#
# Finds the rapidjson library
#
# -----------------------------------------------------------------------------------
#
# Variables used by this module, they can change the default behaviour.
# Those variables need to be either set before calling find_package
# or exported as environment variables before running CMake:
#
# RAPIDJSON_INCLUDEDIR - Set custom include path, useful when rapidjson headers are
# outside system paths
# RAPIDJSON_USE_SSE2 - Configure rapidjson to take advantage of SSE2 capabilities
# RAPIDJSON_USE_SSE42 - Configure rapidjson to take advantage of SSE4.2 capabilities
#
# -----------------------------------------------------------------------------------
#
# Variables defined by this module:
#
# RAPIDJSON_FOUND - True if rapidjson was found
# RAPIDJSON_INCLUDE_DIRS - Path to rapidjson include directory
# RAPIDJSON_CXX_FLAGS - Extra C++ flags required for compilation with rapidjson
#
# -----------------------------------------------------------------------------------
#
# Example usage:
#
# set(RAPIDJSON_USE_SSE2 ON)
# set(RAPIDJSON_INCLUDEDIR "/opt/github.com/rjeczalik/rapidjson/include")
#
# find_package(rapidjson REQUIRED)
#
# include_directories("${RAPIDJSON_INCLUDE_DIRS}")
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}")
# add_executable(foo foo.cc)
#
# -----------------------------------------------------------------------------------
foreach(opt RAPIDJSON_INCLUDEDIR RAPIDJSON_USE_SSE2 RAPIDJSON_USE_SSE42)
if(${opt} AND DEFINED ENV{${opt}} AND NOT ${opt} STREQUAL "$ENV{${opt}}")
message(WARNING "Conflicting ${opt} values: ignoring environment variable and using CMake cache entry.")
elseif(DEFINED ENV{${opt}} AND NOT ${opt})
set(${opt} "$ENV{${opt}}")
endif()
endforeach()
find_path(
RAPIDJSON_INCLUDE_DIRS
NAMES rapidjson/rapidjson.h
PATHS ${RAPIDJSON_INCLUDEDIR}
DOC "Include directory for the rapidjson library."
)
mark_as_advanced(RAPIDJSON_INCLUDE_DIRS)
if(RAPIDJSON_INCLUDE_DIRS)
set(RAPIDJSON_FOUND TRUE)
endif()
mark_as_advanced(RAPIDJSON_FOUND)
if(RAPIDJSON_USE_SSE42)
set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE42")
if(MSVC)
set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE4.2")
else()
set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse4.2")
endif()
else()
if(RAPIDJSON_USE_SSE2)
set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE2")
if(MSVC)
set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE2")
else()
set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse2")
endif()
endif()
endif()
mark_as_advanced(RAPIDJSON_CXX_FLAGS)
if(RAPIDJSON_FOUND)
if(NOT rapidjson_FIND_QUIETLY)
message(STATUS "Found rapidjson header files in ${RAPIDJSON_INCLUDE_DIRS}")
if(DEFINED RAPIDJSON_CXX_FLAGS)
message(STATUS "Found rapidjson C++ extra compilation flags: ${RAPIDJSON_CXX_FLAGS}")
endif()
endif()
elseif(RapidJSON_FIND_REQUIRED)
message(FATAL_ERROR "Could not find rapidjson")
else()
message(STATUS "Optional package rapidjson was not found")
endif()

@ -28,6 +28,7 @@ FIND_LIBRARY(
/usr/local/lib64
/usr/lib
/usr/lib64
/usr/lib/x86_64-linux-gnu/
)
message(STATUS "SCTP LIBRARIES: " ${SCTP_LIBRARIES})

@ -19,6 +19,6 @@
#
SET(SRSLTE_VERSION_MAJOR 19)
SET(SRSLTE_VERSION_MINOR 6)
SET(SRSLTE_VERSION_MINOR 9)
SET(SRSLTE_VERSION_PATCH 0)
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")

@ -2,20 +2,20 @@ cmake_minimum_required(VERSION 2.6)
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@"
WORKING_DIRECTORY "@PROJECT_SOURCE_DIR@"
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@"
WORKING_DIRECTORY "@PROJECT_SOURCE_DIR@"
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "Generating build_info.h")
configure_file(
@CMAKE_SOURCE_DIR@/lib/include/srslte/build_info.h.in
@PROJECT_SOURCE_DIR@/lib/include/srslte/build_info.h.in
@CMAKE_BINARY_DIR@/lib/include/srslte/build_info.h
)

48
debian/changelog vendored

@ -1,8 +1,50 @@
srslte (19.03-0ubuntu1) bionic; urgency=medium
srslte (19.06-0ubuntu1~srslte1~19.04) disco; urgency=medium
* Update to srsLTE 19.03
* Update to srsLTE 19.06 (Ubuntu Disco)
-- srsLTE Packagers <packagers@softwareradiosystems.com> Mon, 13 May 2019 16:50:00 +0200
-- Pedro Alvarez <pedro@softwareradiosystems.com> Fri, 30 August 2019 11:00:03 +0000
srslte (19.06-0ubuntu1~srslte1~18.10) cosmic; urgency=medium
* Update to srsLTE 19.06 (Ubuntu Cosmic)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Fri, 30 August 2019 10:40:03 +0000
srslte (19.06-0ubuntu1~srslte1~18.04) bionic; urgency=medium
* Update to srsLTE 19.06 (Ubuntu Bionic)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Fri, 30 August 2019 09:53:03 +0000
srslte (19.06-0ubuntu1~srslte1~16.04) xenial; urgency=medium
* Update to srsLTE 19.06 (Ubuntu Xenial)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Thu, 29 August 2019 15:00:03 +0000
srslte (19.03-0ubuntu1~srslte1~16.04) xenial; urgency=medium
* Update to srsLTE 19.03 (Ubuntu Xenial)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Tue, 14 May 2019 17:27:03 +0000
srslte (19.03-0ubuntu1~srslte1~19.04) disco; urgency=medium
* Update to srsLTE 19.03 (Ubuntu Disco)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Tue, 14 May 2019 17:27:03 +0000
srslte (19.03-0ubuntu1~srslte1~18.10) cosmic; urgency=medium
* Update to srsLTE 19.03 (Ubuntu Cosmic)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Tue, 14 May 2019 17:27:03 +0000
srslte (19.03-0ubuntu1~srslte1~18.04) bionic; urgency=medium
* Update to srsLTE 19.03 (Ubuntu Bionic)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Tue, 14 May 2019 17:27:03 +0000
srslte (18.12-0ubuntu1) bionic; urgency=medium

44
debian/packager.sh vendored

@ -0,0 +1,44 @@
#!/bin/bash
###################################################################
#
# This file is part of srsLTE.
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
###################################################################
RELEASE=19.06
DISTRO=disco
COMMIT=eda7ca69a09933526e9318bcf553af0dc0b81598
REL_FLAG=releases
echo 'Packaging srsLTE release' $RELEASE 'for Ubuntu' $DISTRO
# Make build dir for the package
BUILD_DIR=~/build-area/srslte_$RELEASE/$REL_FLAG/$DISTRO
mkdir -p $BUILD_DIR
# Make tarball of the package source
pushd ~/srsLTE
git archive $COMMIT -o $BUILD_DIR/srslte_$DISTRO.tar.gz
popd
# Copy original tarball
cp ~/build-area/srslte_$RELEASE/$REL_FLAG/srslte_$RELEASE.orig.tar.gz $BUILD_DIR
mkdir $BUILD_DIR/srsLTE
pushd $BUILD_DIR/srsLTE
tar -vxzf ../srslte_$DISTRO.tar.gz
popd

@ -164,8 +164,6 @@ int main(int argc, char **argv) {
srslte_rf_set_rx_gain(&rf, 50);
}
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
// Supress RF messages
srslte_rf_suppress_stdout(&rf);
@ -202,7 +200,6 @@ int main(int argc, char **argv) {
/* set rf_freq */
srslte_rf_set_rx_freq(&rf, 0, (double)channels[freq].fd * MHZ);
srslte_rf_rx_wait_lo_locked(&rf);
INFO("Set rf_freq to %.3f MHz\n", (double) channels[freq].fd * MHZ/1000000);
printf(
@ -226,7 +223,7 @@ int main(int argc, char **argv) {
exit(-1);
} else if (n > 0) {
for (int i=0;i<3;i++) {
if (found_cells[i].psr > 10.0) {
if (found_cells[i].psr > 2.0) {
srslte_cell_t cell;
cell.id = found_cells[i].cell_id;
cell.cp = found_cells[i].cp;
@ -244,7 +241,7 @@ int main(int argc, char **argv) {
results[n_found_cells].power = found_cells[i].peak;
n_found_cells++;
}
}
}
}
}
}

@ -785,11 +785,6 @@ int main(int argc, char **argv) {
int srate = srslte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4*srate);
} else {
srslte_rf_set_master_clock_rate(&rf, srate);
}
printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000);
float srate_rf = srslte_rf_set_tx_srate(&rf, (double)srate);
if (srate_rf != srate) {

@ -474,12 +474,9 @@ int main(int argc, char **argv) {
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
signal(SIGINT, sig_int_handler);
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
/* set receiver frequency */
printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq) / 1000000);
srslte_rf_set_rx_freq(&rf, prog_args.rf_nof_rx_ant, prog_args.rf_freq + prog_args.file_offset_freq);
srslte_rf_rx_wait_lo_locked(&rf);
uint32_t ntrial = 0;
do {
@ -501,11 +498,6 @@ int main(int argc, char **argv) {
/* set sampling frequency */
int srate = srslte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4 * srate);
} else {
srslte_rf_set_master_clock_rate(&rf, srate);
}
printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000);
float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate);
if (srate_rf != srate) {
@ -606,13 +598,13 @@ int main(int argc, char **argv) {
dl_sf.tdd_config.configured = true;
}
srslte_chest_dl_cfg_t chest_pdsch_cfg;
srslte_chest_dl_cfg_t chest_pdsch_cfg = {};
chest_pdsch_cfg.cfo_estimate_enable = prog_args.enable_cfo_ref;
chest_pdsch_cfg.cfo_estimate_sf_mask = 1023;
chest_pdsch_cfg.interpolate_subframe = !prog_args.average_subframe;
// Special configuration for MBSFN channel estimation
srslte_chest_dl_cfg_t chest_mbsfn_cfg;
srslte_chest_dl_cfg_t chest_mbsfn_cfg = {};
chest_mbsfn_cfg.filter_type = SRSLTE_CHEST_FILTER_TRIANGLE;
chest_mbsfn_cfg.filter_coef[0] = 0.1;
chest_mbsfn_cfg.interpolate_subframe = true;
@ -789,7 +781,7 @@ int main(int argc, char **argv) {
dl_sf.tti = tti;
dl_sf.sf_type = sf_type;
ue_dl_cfg.cfg.tm = (srslte_tm_t)tm;
ue_dl_cfg.pdsch_use_tbs_index_alt = prog_args.enable_256qam;
ue_dl_cfg.cfg.pdsch.use_tbs_index_alt = prog_args.enable_256qam;
if ((ue_dl_cfg.cfg.tm == SRSLTE_TM1 && cell.nof_ports == 1) ||
(ue_dl_cfg.cfg.tm > SRSLTE_TM1 && cell.nof_ports > 1)) {

@ -158,7 +158,7 @@ int main(int argc, char **argv) {
* a) requries more memory but has less latency and is paralellizable.
*/
for (N_id_2=0;N_id_2<3;N_id_2++) {
if (srslte_pss_init(&pss[N_id_2], frame_length)) {
if (srslte_pss_init_fft(&pss[N_id_2], frame_length, symbol_sz)) {
ERROR("Error initializing PSS object\n");
exit(-1);
}
@ -166,7 +166,7 @@ int main(int argc, char **argv) {
ERROR("Error initializing N_id_2\n");
exit(-1);
}
if (srslte_sss_init(&sss[N_id_2], 128)) {
if (srslte_sss_init(&sss[N_id_2], symbol_sz)) {
ERROR("Error initializing SSS object\n");
exit(-1);
}
@ -220,10 +220,15 @@ int main(int argc, char **argv) {
cfo[frame_cnt] = srslte_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]);
printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n",
frame_cnt,N_id_2, srslte_sss_N_id_1(&sss[N_id_2], m0, m1),
srslte_sss_subframe(m0, m1), peak_value[N_id_2],
peak_pos[N_id_2], m0, m1,
cfo[frame_cnt]);
frame_cnt,
N_id_2,
srslte_sss_N_id_1(&sss[N_id_2], m0, m1, m1_value + m0_value),
srslte_sss_subframe(m0, m1),
peak_value[N_id_2],
peak_pos[N_id_2],
m0,
m1,
cfo[frame_cnt]);
}
}
gettimeofday(&tdata[2], NULL);

@ -123,7 +123,6 @@ int main(int argc, char **argv) {
ERROR("Error opening rf\n");
exit(-1);
}
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
sigset_t sigset;
sigemptyset(&sigset);
@ -134,11 +133,6 @@ int main(int argc, char **argv) {
printf("Set RX gain: %.2f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain));
float srate = srslte_rf_set_rx_srate(&rf, rf_rate);
if (srate != rf_rate) {
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4*rf_rate);
} else {
srslte_rf_set_master_clock_rate(&rf, rf_rate);
}
srate = srslte_rf_set_rx_srate(&rf, rf_rate);
if (srate != rf_rate) {
ERROR("Error setting samplign frequency %.2f MHz\n", rf_rate * 1e-6);
@ -147,7 +141,6 @@ int main(int argc, char **argv) {
}
printf("Correctly RX rate: %.2f MHz\n", srate*1e-6);
srslte_rf_rx_wait_lo_locked(&rf);
srslte_rf_start_rx_stream(&rf, false);

@ -100,7 +100,11 @@ void parse_args(int argc, char **argv) {
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return srslte_rf_recv_with_time_multi(h, (void**)data[0], nsamples, true, NULL, NULL);
void* ptr[SRSLTE_MAX_PORTS];
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
ptr[i] = data[i];
}
return srslte_rf_recv_with_time_multi(h, ptr, nsamples, true, NULL, NULL);
}
int main(int argc, char **argv) {
@ -122,7 +126,6 @@ int main(int argc, char **argv) {
ERROR("Error opening rf\n");
exit(-1);
}
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
for (int i = 0; i < nof_rx_antennas; i++) {
buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100));
@ -137,11 +140,6 @@ int main(int argc, char **argv) {
printf("Set RX gain: %.1f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain));
int srate = srslte_sampling_freq_hz(nof_prb);
if (srate != -1) {
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4*srate);
} else {
srslte_rf_set_master_clock_rate(&rf, srate);
}
printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000);
float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate);
if (srate_rf != srate) {
@ -152,7 +150,6 @@ int main(int argc, char **argv) {
ERROR("Invalid number of PRB %d\n", nof_prb);
exit(-1);
}
srslte_rf_rx_wait_lo_locked(&rf);
srslte_rf_start_rx_stream(&rf, false);
cell.cp = SRSLTE_CP_NORM;

@ -136,14 +136,8 @@ int main(int argc, char **argv) {
ERROR("Error opening rf\n");
exit(-1);
}
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
int srate = srslte_sampling_freq_hz(nof_prb);
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4*srate);
} else {
srslte_rf_set_master_clock_rate(&rf, srate);
}
int srate = srslte_sampling_freq_hz(nof_prb);
srslte_rf_set_rx_srate(&rf, (double) srate);
srslte_rf_set_tx_srate(&rf, (double) srate);

@ -23,6 +23,7 @@
#define SRSASN_COMMON_UTILS_H
#include <algorithm>
#include <array>
#include <cmath>
#include <cstring>
#include <sstream>
@ -80,8 +81,13 @@ ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_
class bit_ref
{
public:
bit_ref();
bit_ref(uint8_t* start_ptr_, uint32_t max_size_);
bit_ref() = default;
bit_ref(uint8_t* start_ptr_, uint32_t max_size_) :
ptr(start_ptr_),
start_ptr(start_ptr_),
max_ptr(max_size_ + start_ptr_)
{
}
int distance(const bit_ref& other) const;
int distance(uint8_t* ref_ptr) const;
@ -90,6 +96,7 @@ public:
int distance_bytes() const;
SRSASN_CODE pack(uint32_t val, uint32_t n_bits);
SRSASN_CODE pack_bytes(const uint8_t* buf, uint32_t n_bytes);
template <class T>
SRSASN_CODE unpack(T& val, uint32_t n_bits)
{
@ -97,15 +104,17 @@ public:
val = ret.val;
return ret.code;
}
SRSASN_CODE unpack_bytes(uint8_t* buf, uint32_t n_bytes);
SRSASN_CODE align_bytes();
SRSASN_CODE align_bytes_zero();
SRSASN_CODE advance_bits(uint32_t n_bits);
void set(uint8_t* start_ptr_, uint32_t max_size_);
private:
uint8_t* ptr;
uint8_t offset;
uint8_t* start_ptr;
uint8_t* max_ptr;
uint8_t* ptr = nullptr;
uint8_t offset = 0;
uint8_t* start_ptr = nullptr;
uint8_t* max_ptr = nullptr;
};
/*********************
@ -116,7 +125,7 @@ class dyn_array
{
public:
typedef T item_type;
dyn_array() : data_(NULL), size_(0), cap_(0) {}
dyn_array() = default;
dyn_array(uint32_t new_size) : size_(new_size), cap_(new_size) { data_ = new T[size_]; }
dyn_array(const dyn_array<T>& other)
{
@ -183,8 +192,9 @@ public:
const T* data() const { return &data_[0]; }
private:
T* data_;
uint32_t size_, cap_;
T* data_ = nullptr;
uint32_t size_ = 0;
uint32_t cap_ = 0;
};
template <class T, uint32_t MAX_N>
@ -219,24 +229,6 @@ private:
uint32_t current_size;
};
template <class T, uint32_t N>
class fixed_array
{
public:
typedef T item_type;
static uint32_t size() { return N; }
T& operator[](uint32_t idx) { return data_[idx]; }
const T& operator[](uint32_t idx) const { return data_[idx]; }
bool operator==(const fixed_array<T, N>& other) const { return std::equal(data_, data_ + size(), other.data_); }
T& back() { return data_[size() - 1]; }
const T& back() const { return data_[size() - 1]; }
T* data() { return &data_[0]; }
const T* data() const { return &data_[0]; }
private:
T data_[N];
};
/*********************
ext packing
*********************/
@ -341,22 +333,21 @@ template <class IntType>
SRSASN_CODE unpack_unalign_integer(IntType& n, bit_ref& bref, IntType lb, IntType ub);
template <class IntType>
struct UnalignedIntegerPacker {
UnalignedIntegerPacker(IntType, IntType);
IntType lb;
IntType ub;
SRSASN_CODE pack(bit_ref& bref, IntType n) const;
SRSASN_CODE unpack(IntType& n, bit_ref& bref) const;
UnalignedIntegerPacker(IntType lb_, IntType ub_) : lb(lb_), ub(ub_) {}
const IntType lb;
const IntType ub;
SRSASN_CODE pack(bit_ref& bref, IntType n) const;
SRSASN_CODE unpack(IntType& n, bit_ref& bref) const;
};
template <class IntType, IntType lb, IntType ub>
struct unaligned_integer {
IntType value;
const UnalignedIntegerPacker<IntType> packer;
unaligned_integer() : packer(lb, ub) {}
unaligned_integer(IntType value_) : value(value_), packer(lb, ub) {}
IntType value;
unaligned_integer() = default;
unaligned_integer(IntType value_) : value(value_) {}
operator IntType() { return value; }
SRSASN_CODE pack(bit_ref& bref) const { return packer.pack(bref, value); }
SRSASN_CODE unpack(bit_ref& bref) { return packer.unpack(value, bref); }
SRSASN_CODE pack(bit_ref& bref) const { return pack_unalign_integer(bref, value, lb, ub); }
SRSASN_CODE unpack(bit_ref& bref) { return unpack_unalign_integer(value, bref, lb, ub); }
};
template <class IntType>
@ -486,7 +477,7 @@ public:
SRSASN_CODE unpack(bit_ref& bref);
private:
fixed_array<uint8_t, N> octets_;
std::array<uint8_t, N> octets_;
};
template <uint32_t N>
@ -520,7 +511,7 @@ SRSASN_CODE fixed_octstring<N>::unpack(bit_ref& bref)
class dyn_octstring
{
public:
dyn_octstring() {}
dyn_octstring() = default;
dyn_octstring(uint32_t new_size) : octets_(new_size) {}
const uint8_t& operator[](uint32_t idx) const { return octets_[idx]; }
@ -621,7 +612,7 @@ public:
SRSASN_CODE unpack(bit_ref& bref, bool& ext) { return unpack_fixed_bitstring(data(), ext, bref, N); }
private:
fixed_array<uint8_t, (uint32_t)((N + 7) / 8)> octets_; // ceil(N/8.0)
std::array<uint8_t, (uint32_t)((N + 7) / 8)> octets_; // ceil(N/8.0)
};
/*********************
@ -874,16 +865,15 @@ template <class T>
class copy_ptr
{
public:
copy_ptr() : ptr(NULL) {}
explicit copy_ptr(T* ptr_) :
explicit copy_ptr(T* ptr_ = nullptr) :
ptr(ptr_) {} // it takes hold of the pointer (including destruction). You should use make_copy_ptr() in most cases
// instead of this ctor
copy_ptr(const copy_ptr<T>& other) { ptr = other.make_obj_(); } // it allocates new memory for the new object
// instead of this ctor
copy_ptr(const copy_ptr<T>& other) { ptr = (other.ptr == nullptr) ? nullptr : new T(*other.ptr); }
~copy_ptr() { destroy_(); }
copy_ptr<T>& operator=(const copy_ptr<T>& other)
{
if (this != &other) {
acquire(other.make_obj_());
reset((other.ptr == nullptr) ? nullptr : new T(*other.ptr));
}
return *this;
}
@ -897,15 +887,23 @@ public:
T* release()
{
T* ret = ptr;
ptr = NULL;
ptr = nullptr;
return ret;
}
void acquire(T* ptr_)
void reset(T* ptr_ = nullptr)
{
destroy_();
ptr = ptr_;
}
void reset() { acquire(NULL); }
void set_present(bool flag = true)
{
if (flag) {
reset(new T());
} else {
reset();
}
}
bool is_present() const { return get() != nullptr; }
private:
void destroy_()
@ -914,7 +912,6 @@ private:
delete ptr;
}
}
T* make_obj_() const { return (ptr == NULL) ? NULL : new T(*ptr); }
T* ptr;
};
@ -928,23 +925,31 @@ copy_ptr<T> make_copy_ptr(const T& t)
ext group
*********************/
class ext_groups_header
class ext_groups_packer_guard
{
public:
ext_groups_header(uint32_t max_nof_groups, uint32_t nof_nogroups_ = 0);
bool& operator[](uint32_t idx);
SRSASN_CODE pack_nof_groups(bit_ref& bref) const;
SRSASN_CODE pack_group_flags(bit_ref& bref) const;
bool& operator[](uint32_t idx);
SRSASN_CODE pack(bit_ref& bref) const;
SRSASN_CODE unpack_nof_groups(bit_ref& bref);
SRSASN_CODE unpack_group_flags(bit_ref& bref);
private:
bounded_array<bool, 20> groups;
};
class ext_groups_unpacker_guard
{
public:
explicit ext_groups_unpacker_guard(uint32_t nof_supported_groups_);
~ext_groups_unpacker_guard();
void resize(uint32_t new_size);
bool& operator[](uint32_t idx);
SRSASN_CODE unpack(bit_ref& bref);
private:
mutable uint32_t nof_groups;
const uint32_t nof_nogroups;
bounded_array<bool, 20> groups;
const uint32_t nof_supported_groups;
uint32_t nof_unpacked_groups = 0;
bit_ref* bref_tracker = nullptr;
};
/*********************

@ -2939,6 +2939,8 @@ typedef struct {
} LIBLTE_MME_ID_RESPONSE_MSG_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT* msg);
LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_response_msg(LIBLTE_BYTE_MSG_STRUCT* msg,
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp);

File diff suppressed because it is too large Load Diff

@ -34,6 +34,23 @@ struct plmn_id_s;
struct s_tmsi_s;
struct rlc_cfg_c;
struct srb_to_add_mod_s;
struct sched_request_cfg_c;
struct mac_main_cfg_s;
struct rach_cfg_common_s;
struct time_align_timer_opts;
struct phys_cfg_ded_s;
struct prach_cfg_info_s;
struct pdsch_cfg_common_s;
struct pusch_cfg_common_s;
struct pucch_cfg_common_s;
struct srs_ul_cfg_common_c;
struct ul_pwr_ctrl_common_s;
struct scell_to_add_mod_r10_s;
struct mbms_notif_cfg_r9_s;
struct mbsfn_area_info_r9_s;
struct mbsfn_sf_cfg_s;
struct mcch_msg_s;
struct sib_type13_r9_s;
} // namespace rrc
} // namespace asn1
@ -49,9 +66,41 @@ void to_asn1(asn1::rrc::plmn_id_s* asn1_type, const plmn_id_t& cfg);
s_tmsi_t make_s_tmsi_t(const asn1::rrc::s_tmsi_s& asn1_type);
void to_asn1(asn1::rrc::s_tmsi_s* asn1_type, const s_tmsi_t& cfg);
/***************************
* RLC Config
**************************/
rlc_config_t make_rlc_config_t(const asn1::rrc::rlc_cfg_c& asn1_type);
rlc_config_t make_rlc_config_t(const asn1::rrc::srb_to_add_mod_s& asn1_type);
void to_asn1(asn1::rrc::rlc_cfg_c* asn1_type, const rlc_config_t& cfg);
}
/***************************
* MAC Config
**************************/
void set_mac_cfg_t_sched_request_cfg(mac_cfg_t* cfg, const asn1::rrc::sched_request_cfg_c& asn1_type);
void set_mac_cfg_t_main_cfg(mac_cfg_t* cfg, const asn1::rrc::mac_main_cfg_s& asn1_type);
void set_mac_cfg_t_rach_cfg_common(mac_cfg_t* cfg, const asn1::rrc::rach_cfg_common_s& asn1_type);
void set_mac_cfg_t_time_alignment(mac_cfg_t* cfg, const asn1::rrc::time_align_timer_opts asn1_type);
/***************************
* PHY Config
**************************/
void set_phy_cfg_t_dedicated_cfg(phy_cfg_t* cfg, const asn1::rrc::phys_cfg_ded_s& asn1_type);
void set_phy_cfg_t_common_prach(phy_cfg_t* cfg, const asn1::rrc::prach_cfg_info_s* asn1_type, uint32_t root_seq_idx);
void set_phy_cfg_t_common_pdsch(phy_cfg_t* cfg, const asn1::rrc::pdsch_cfg_common_s& asn1_type);
void set_phy_cfg_t_common_pusch(phy_cfg_t* cfg, const asn1::rrc::pusch_cfg_common_s& asn1_type);
void set_phy_cfg_t_common_pucch(phy_cfg_t* cfg, const asn1::rrc::pucch_cfg_common_s& asn1_type);
void set_phy_cfg_t_common_srs(phy_cfg_t* cfg, const asn1::rrc::srs_ul_cfg_common_c& asn1_type);
void set_phy_cfg_t_common_pwr_ctrl(phy_cfg_t* cfg, const asn1::rrc::ul_pwr_ctrl_common_s& asn1_type);
void set_phy_cfg_t_scell_config(phy_cfg_t* cfg, const asn1::rrc::scell_to_add_mod_r10_s& asn1_type);
void set_phy_cfg_t_enable_64qam(phy_cfg_t* cfg, const bool enabled);
// mbms
mbms_notif_cfg_t make_mbms_notif_cfg(const asn1::rrc::mbms_notif_cfg_r9_s& asn1_type);
mbsfn_area_info_t make_mbsfn_area_info(const asn1::rrc::mbsfn_area_info_r9_s& asn1_type);
mbsfn_sf_cfg_t make_mbsfn_sf_cfg(const asn1::rrc::mbsfn_sf_cfg_s& sf_cfg);
mcch_msg_t make_mcch_msg(const asn1::rrc::mcch_msg_s& asn1_type);
sib13_t make_sib13(const asn1::rrc::sib_type13_r9_s& asn1_type);
} // namespace srslte
#endif // SRSLTE_RRC_ASN1_UTILS_H

@ -156,14 +156,12 @@ inline bool bytes_to_mnc(const uint8_t* bytes, uint16_t* mnc, uint8_t len)
if (len != 3 && len != 2) {
*mnc = 0;
return false;
}
if (len == 3) {
} else if (len == 3) {
*mnc = 0xF000;
*mnc |= ((uint16_t)bytes[0]) << 8u;
*mnc |= ((uint16_t)bytes[1]) << 4u;
*mnc |= ((uint16_t)bytes[2]) << 0u;
}
if (len == 2) {
} else if (len == 2) {
*mnc = 0xFF00;
*mnc |= ((uint16_t)bytes[0]) << 4u;
*mnc |= ((uint16_t)bytes[1]) << 0u;

@ -242,6 +242,6 @@ allocate_unique_buffer(byte_buffer_pool& pool, const char* debug_name, bool bloc
return std::move(unique_byte_buffer_t(pool.allocate(debug_name, blocking), byte_buffer_deleter(&pool)));
}
} // namespace srsue
} // namespace srslte
#endif // SRSLTE_BUFFER_POOL_H

@ -28,15 +28,12 @@ namespace srslte {
* Safe conversions between byte buffers and integer types.
* Note: these don't perform endian conversion - use e.g. htonl/ntohl if required
*****************************************************************************/
inline void uint8_to_uint32(uint8_t *buf, uint32_t *i)
inline void uint8_to_uint32(uint8_t* buf, uint32_t* i)
{
*i = (uint32_t)buf[0] << 24 |
(uint32_t)buf[1] << 16 |
(uint32_t)buf[2] << 8 |
(uint32_t)buf[3];
*i = (uint32_t)buf[0] << 24 | (uint32_t)buf[1] << 16 | (uint32_t)buf[2] << 8 | (uint32_t)buf[3];
}
inline void uint32_to_uint8(uint32_t i, uint8_t *buf)
inline void uint32_to_uint8(uint32_t i, uint8_t* buf)
{
buf[0] = (i >> 24) & 0xFF;
buf[1] = (i >> 16) & 0xFF;
@ -44,18 +41,28 @@ inline void uint32_to_uint8(uint32_t i, uint8_t *buf)
buf[3] = i & 0xFF;
}
inline void uint8_to_uint16(uint8_t *buf, uint16_t *i)
inline void uint8_to_uint16(uint8_t* buf, uint16_t* i)
{
*i = (uint32_t)buf[0] << 8 |
(uint32_t)buf[1];
*i = (uint32_t)buf[0] << 8 | (uint32_t)buf[1];
}
inline void uint16_to_uint8(uint16_t i, uint8_t *buf)
inline void uint16_to_uint8(uint16_t i, uint8_t* buf)
{
buf[0] = (i >> 8) & 0xFF;
buf[1] = i & 0xFF;
}
}; //namespace
inline void uint8_to_uint24(uint8_t* buf, uint32_t* i)
{
*i = (uint32_t)buf[0] << 16 | (uint32_t)buf[1] << 8 | (uint32_t)buf[2];
}
inline void uint24_to_uint8(uint32_t i, uint8_t* buf)
{
buf[0] = (i >> 16) & 0xFF;
buf[1] = (i >> 8) & 0xFF;
buf[2] = i & 0xFF;
}
} // namespace srslte
#endif // SRSLTE_INT_HELPERS_H

@ -67,22 +67,36 @@ public:
uint32_t lcid;
};
const uint8_t PDCP_SN_LEN_5 = 5;
const uint8_t PDCP_SN_LEN_7 = 7;
const uint8_t PDCP_SN_LEN_12 = 12;
const uint8_t PDCP_SN_LEN_18 = 18;
class srslte_pdcp_config_t
typedef enum { PDCP_RB_IS_SRB, PDCP_RB_IS_DRB } pdcp_rb_type_t;
class pdcp_config_t
{
public:
srslte_pdcp_config_t(uint8_t bearer_id_ = 0, bool is_control_ = false, bool is_data_ = false, uint8_t direction_ = SECURITY_DIRECTION_UPLINK)
:bearer_id(bearer_id_)
,direction(direction_)
,is_control(is_control_)
,is_data(is_data_)
,sn_len(12) {}
uint32_t bearer_id;
uint8_t direction;
bool is_control;
bool is_data;
uint8_t sn_len;
pdcp_config_t(uint8_t bearer_id_,
pdcp_rb_type_t rb_type_,
security_direction_t tx_direction_,
security_direction_t rx_direction_,
uint8_t sn_len_) :
bearer_id(bearer_id_),
rb_type(rb_type_),
tx_direction(tx_direction_),
rx_direction(rx_direction_),
sn_len(sn_len_)
{
hdr_len_bytes = ceil((float)sn_len / 8);
}
uint8_t bearer_id = 1;
pdcp_rb_type_t rb_type = PDCP_RB_IS_DRB;
security_direction_t tx_direction = SECURITY_DIRECTION_DOWNLINK;
security_direction_t rx_direction = SECURITY_DIRECTION_UPLINK;
uint8_t sn_len = PDCP_SN_LEN_12;
uint8_t hdr_len_bytes = 2;
// TODO: Support the following configurations
// bool do_rohc;

@ -103,6 +103,7 @@ typedef enum {
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_EEA0 = 0,
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_128_EEA1,
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_128_EEA2,
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_128_EEA3,
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_N_ITEMS,
} LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM;
static const char liblte_security_ciphering_algorithm_id_text[LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_N_ITEMS][20] = {
@ -111,6 +112,7 @@ typedef enum {
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_EIA0 = 0,
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_128_EIA1,
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_128_EIA2,
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_128_EIA3,
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_N_ITEMS,
} LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM;
static const char liblte_security_integrity_algorithm_id_text[LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {
@ -177,6 +179,8 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* mac);
LIBLTE_ERROR_ENUM liblte_security_128_eia2(
uint8* key, uint32 count, uint8 bearer, uint8 direction, LIBLTE_BIT_MSG_STRUCT* msg, uint8* mac);
LIBLTE_ERROR_ENUM liblte_security_128_eia3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* mac);
/*********************************************************************
Name: liblte_security_encryption_eea1
@ -224,6 +228,12 @@ LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(
LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* ct, uint32 ct_len, uint8* out);
LIBLTE_ERROR_ENUM liblte_security_encryption_eea3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* out);
LIBLTE_ERROR_ENUM liblte_security_decryption_eea3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* out);
/*********************************************************************
Name: liblte_security_milenage_f1

@ -65,9 +65,7 @@ public:
tti = 0;
level = LOG_LEVEL_NONE;
hex_limit = 0;
show_layer_en = true;
add_string_en = false;
level_text_short = true;
}
log(std::string service_name_) {
@ -75,9 +73,7 @@ public:
tti = 0;
level = LOG_LEVEL_NONE;
hex_limit = 0;
show_layer_en = true;
add_string_en = false;
level_text_short = true;
}
virtual ~log() {};
@ -131,12 +127,6 @@ public:
int get_hex_limit() {
return hex_limit;
}
void set_log_level_short(bool enable) {
level_text_short = enable;
}
void show_layer(bool enable) {
show_layer_en = enable;
}
// Pure virtual methods for logging
virtual void console(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
@ -144,6 +134,7 @@ public:
virtual void warning(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void info(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void debug_long(const char* message, ...) __attribute__((format(printf, 2, 3))) = 0;
// Same with hex dump
virtual void error_hex(const uint8_t *, int, const char *, ...) __attribute__((format (printf, 4, 5)))
@ -162,8 +153,6 @@ protected:
int hex_limit;
std::string service_name;
bool show_layer_en;
bool level_text_short;
bool add_string_en;
std::string add_string_val;
};

@ -58,6 +58,7 @@ public:
void warning(const char * message, ...) __attribute__ ((format (printf, 2, 3)));
void info(const char * message, ...) __attribute__ ((format (printf, 2, 3)));
void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3)));
void debug_long(const char* message, ...) __attribute__((format(printf, 2, 3)));
void error_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5)));
void warning_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5)));
@ -82,18 +83,24 @@ protected:
logger *logger_h;
bool do_tti;
static const int char_buff_size = logger::preallocated_log_str_size - 64 * 3;
time_itf *time_src;
time_format_t time_format;
logger_stdout def_logger_stdout;
void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, const char *msg);
void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, const char *msg, const uint8_t *hex, int size);
void all_log_line(srslte::LOG_LEVEL_ENUM level, uint32_t tti, std::string file, int line, char *msg);
std::string now_time();
void all_log(srslte::LOG_LEVEL_ENUM level,
uint32_t tti,
const char* msg,
const uint8_t* hex = nullptr,
int size = 0,
bool long_msg = false);
void now_time(char* buffer, const uint32_t buffer_len);
void get_tti_str(const uint32_t tti_, char* buffer, const uint32_t buffer_len);
std::string hex_string(const uint8_t *hex, int size);
};
} // namespace srsue
} // namespace srslte
#endif // SRSLTE_LOG_FILTER_H

@ -27,6 +27,8 @@
#ifndef SRSLTE_LOGGER_H
#define SRSLTE_LOGGER_H
#include "buffer_pool.h"
#include <memory>
#include <stdio.h>
#include <string>
@ -35,7 +37,70 @@ namespace srslte {
class logger
{
public:
virtual void log(std::string *msg) = 0;
const static uint32_t preallocated_log_str_size = 1024;
logger() : pool(16 * 1024) {}
class log_str
{
public:
log_str(const char* msg_ = nullptr, uint32_t size_ = 0)
{
size = size_ ? size_ : preallocated_log_str_size;
msg = new char[size];
if (msg_) {
strncpy(msg, msg_, size);
} else {
msg[0] = '\0';
}
}
log_str(const log_str&) = delete;
log_str& operator=(const log_str&) = delete;
~log_str() { delete[] msg; }
void reset() { msg[0] = '\0'; }
char* str() { return msg; }
uint32_t get_buffer_size() { return size; }
private:
uint32_t size;
char* msg;
};
typedef buffer_pool<log_str> log_str_pool_t;
class log_str_deleter
{
public:
explicit log_str_deleter(log_str_pool_t* pool_ = nullptr) : pool(pool_) {}
void operator()(log_str* buf)
{
if (buf) {
if (pool) {
buf->reset();
pool->deallocate(buf);
} else {
delete buf;
}
}
}
private:
log_str_pool_t* pool;
};
typedef std::unique_ptr<log_str, log_str_deleter> unique_log_str_t;
void log_char(const char* msg) { log(std::move(unique_log_str_t(new log_str(msg), log_str_deleter()))); }
virtual void log(unique_log_str_t msg) = 0;
log_str_pool_t& get_pool() { return pool; }
unique_log_str_t allocate_unique_log_str()
{
return unique_log_str_t(pool.allocate(), logger::log_str_deleter(&pool));
}
private:
log_str_pool_t pool;
};
} // namespace srslte

@ -47,9 +47,9 @@ public:
logger_file(std::string file);
~logger_file();
void init(std::string file, int max_length = -1);
void stop();
// Implementation of log_out
void log(str_ptr msg);
void log(const char *msg);
void log(unique_log_str_t msg);
private:
void run_thread();
@ -63,7 +63,8 @@ private:
std::string filename;
pthread_cond_t not_empty;
pthread_mutex_t mutex;
std::deque<str_ptr> buffer;
std::deque<unique_log_str_t> buffer;
};
} // namespace srslte

@ -36,12 +36,7 @@ namespace srslte {
class logger_stdout : public logger
{
public:
void log(std::string *msg) {
if (msg) {
fprintf(stdout, "%s", msg->c_str());
delete msg;
}
}
void log(unique_log_str_t log_str) { fprintf(stdout, "%s", log_str->str()); }
};
} // namespace srslte

@ -0,0 +1,65 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_MAC_NR_PCAP_H
#define SRSLTE_MAC_NR_PCAP_H
#include "srslte/common/pcap.h"
#include <stdint.h>
#include <string>
namespace srslte {
class mac_nr_pcap
{
public:
mac_nr_pcap();
~mac_nr_pcap();
void enable(const bool& enable_);
void open(const std::string& filename, const uint16_t& ue_id = 0);
void close();
void set_ue_id(const uint16_t& ue_id);
void write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint8_t harqid, uint32_t tti);
void write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_ra_rnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_si_rnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
private:
bool enable_write = false;
std::string filename;
FILE* pcap_file = nullptr;
uint32_t ue_id = 0;
void pack_and_write(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint32_t tti,
uint16_t crnti_,
uint8_t harqid,
uint8_t direction,
uint8_t rnti_type);
};
} // namespace srslte
#endif // SRSLTE_MAC_NR_PCAP_H

@ -0,0 +1,118 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_MAC_NR_PDU_H
#define SRSLTE_MAC_NR_PDU_H
#include "srslte/common/common.h"
#include <memory>
#include <stdint.h>
#include <vector>
namespace srslte {
class mac_nr_sch_pdu;
class mac_nr_sch_subpdu
{
public:
// 3GPP 38.321 v15.3.0 Combined Tables 6.2.1-1, 6.2.1-2
typedef enum {
// Values for DL-SCH
DRX_CMD = 0b111100,
TA_CMD = 0b111101,
CON_RES_ID = 0b111110,
// Values for UL-SCH
CRNTI = 0b111010,
SHORT_TRUNC_BSR = 0b111011,
LONG_TRUNC_BSR = 0b111100,
SHORT_BSR = 0b111101,
LONG_BSR = 0b111110,
// Common
CCCH = 0b000000,
PADDING = 0b111111,
} nr_lcid_sch_t;
mac_nr_sch_subpdu(mac_nr_sch_pdu* parent_);
nr_lcid_sch_t get_type();
bool is_sdu();
bool is_var_len_ce();
uint32_t read_subheader(const uint8_t* ptr);
uint32_t get_total_length();
uint32_t get_sdu_length();
uint32_t get_lcid();
uint8_t* get_sdu();
void set_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_);
void set_padding(const uint32_t len_);
uint32_t write_subpdu(const uint8_t* start_);
private:
uint32_t sizeof_ce(uint32_t lcid, bool is_ul);
// protected:
uint32_t lcid = 0;
int header_length = 0;
int sdu_length = 0;
bool F_bit = false;
uint8_t* sdu = nullptr;
mac_nr_sch_pdu* parent = nullptr;
};
class mac_nr_sch_pdu
{
public:
mac_nr_sch_pdu(bool ulsch_ = false) : ulsch(ulsch_) {}
void pack();
void unpack(const uint8_t* payload, const uint32_t& len);
uint32_t get_num_subpdus();
const mac_nr_sch_subpdu& get_subpdu(const uint32_t& index);
bool is_ulsch();
void init_tx(byte_buffer_t* buffer_, uint32_t pdu_len_, bool is_ulsch_ = false);
uint32_t add_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_);
uint32_t get_remaing_len();
private:
uint32_t size_header_sdu(const uint32_t nbytes);
bool ulsch = false;
std::vector<mac_nr_sch_subpdu> subpdus;
byte_buffer_t* buffer = nullptr;
uint32_t pdu_len = 0;
uint32_t remaining_len = 0;
};
} // namespace srslte
#endif // SRSLTE_MAC_NR_PDU_H

@ -0,0 +1,230 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: multiqueue.h
* Description: General-purpose non-blocking multiqueue. It behaves as a list
* of bounded/unbounded queues.
*****************************************************************************/
#ifndef SRSLTE_MULTIQUEUE_H
#define SRSLTE_MULTIQUEUE_H
#include <algorithm>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <vector>
namespace srslte {
template <typename myobj>
class multiqueue_handler
{
// NOTE: needed to create a queue wrapper to make its move ctor noexcept.
// otherwise we couldnt use the resize method of std::vector<queue<myobj>> if myobj is move-only
class queue_wrapper : private std::queue<myobj>
{
public:
queue_wrapper() = default;
queue_wrapper(queue_wrapper&& other) noexcept : std::queue<myobj>(std::move(other)) {}
using std::queue<myobj>::push;
using std::queue<myobj>::pop;
using std::queue<myobj>::size;
using std::queue<myobj>::empty;
using std::queue<myobj>::front;
std::condition_variable cv_full;
bool active = true;
};
public:
explicit multiqueue_handler(uint32_t capacity_ = std::numeric_limits<uint32_t>::max()) : capacity(capacity_) {}
~multiqueue_handler() { reset(); }
void reset()
{
std::unique_lock<std::mutex> lock(mutex);
running = false;
while (nof_threads_waiting > 0) {
uint32_t size = queues.size();
lock.unlock();
cv_empty.notify_one();
for (uint32_t i = 0; i < size; ++i) {
queues[i].cv_full.notify_all();
}
lock.lock();
// wait for all threads to unblock
cv_exit.wait(lock);
}
queues.clear();
}
int add_queue()
{
uint32_t qidx = 0;
std::lock_guard<std::mutex> lock(mutex);
if (not running) {
return -1;
}
for (; qidx < queues.size() and queues[qidx].active; ++qidx)
;
if (qidx == queues.size()) {
// create new queue
queues.emplace_back();
} else {
queues[qidx].active = true;
}
return (int)qidx;
}
int nof_queues()
{
std::lock_guard<std::mutex> lock(mutex);
uint32_t count = 0;
for (uint32_t i = 0; i < queues.size(); ++i) {
count += queues[i].active ? 1 : 0;
}
return count;
}
template <typename FwdRef>
void push(int q_idx, FwdRef&& value)
{
{
std::unique_lock<std::mutex> lock(mutex);
while (is_queue_active_(q_idx) and queues[q_idx].size() >= capacity) {
nof_threads_waiting++;
queues[q_idx].cv_full.wait(lock);
nof_threads_waiting--;
}
if (not is_queue_active_(q_idx)) {
cv_exit.notify_one();
return;
}
queues[q_idx].push(std::forward<FwdRef>(value));
}
cv_empty.notify_one();
}
bool try_push(int q_idx, const myobj& value)
{
{
std::lock_guard<std::mutex> lock(mutex);
if (not is_queue_active_(q_idx) or queues[q_idx].size() >= capacity) {
return false;
}
queues[q_idx].push(value);
}
cv_empty.notify_one();
return true;
}
std::pair<bool, myobj> try_push(int q_idx, myobj&& value)
{
{
std::lock_guard<std::mutex> lck(mutex);
if (not is_queue_active_(q_idx) or queues[q_idx].size() >= capacity) {
return {false, std::move(value)};
}
queues[q_idx].push(std::move(value));
}
cv_empty.notify_one();
return {true, std::move(value)};
}
int wait_pop(myobj* value)
{
std::unique_lock<std::mutex> lock(mutex);
while (running) {
// Round-robin for all queues
for (const queue_wrapper& q : queues) {
spin_idx = (spin_idx + 1) % queues.size();
if (is_queue_active_(spin_idx) and not queues[spin_idx].empty()) {
if (value) {
*value = std::move(queues[spin_idx].front());
}
queues[spin_idx].pop();
if (nof_threads_waiting > 0) {
lock.unlock();
queues[spin_idx].cv_full.notify_one();
}
return spin_idx;
}
}
nof_threads_waiting++;
cv_empty.wait(lock);
nof_threads_waiting--;
}
cv_exit.notify_one();
return -1;
}
bool empty(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
return queues[qidx].empty();
}
size_t size(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
return queues[qidx].size();
}
const myobj& front(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
return queues[qidx].front();
}
void erase_queue(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
if (is_queue_active_(qidx)) {
queues[qidx].active = false;
while (not queues[qidx].empty()) {
queues[qidx].pop();
}
}
}
bool is_queue_active(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
return is_queue_active_(qidx);
}
private:
bool is_queue_active_(int qidx) const { return running and queues[qidx].active; }
std::mutex mutex;
std::condition_variable cv_empty, cv_exit;
uint32_t spin_idx = 0;
bool running = true;
std::vector<queue_wrapper> queues;
uint32_t capacity = 0;
uint32_t nof_threads_waiting = 0;
};
} // namespace srslte
#endif // SRSLTE_MULTIQUEUE_H

@ -0,0 +1,77 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/*! \brief Base class for implementing socket handlers using
* the netsource object.
*
*/
#ifndef SRSLTE_NETSOURE_HANDLER_H
#define SRSLTE_NETSOURE_HANDLER_H
#include "srslte/common/log.h"
#include "srslte/common/threads.h"
#include "srslte/phy/io/netsource.h"
#include <array>
#include <iostream>
#include <memory>
class netsource_handler : public thread
{
public:
netsource_handler(const std::string name_) : thread(name_) { rx_buf = unique_byte_array_t(new byte_array_t); }
~netsource_handler(){};
void stop()
{
run_enable = false;
int cnt = 0;
while (running && cnt < 100) {
usleep(10000);
cnt++;
}
if (running) {
thread_cancel();
}
wait_thread_finish();
}
virtual void run_thread() = 0;
bool run_enable = true;
bool running = false;
bool initialized = false;
std::string net_ip = "0.0.0.0";
uint32_t net_port = 0;
const static uint32_t RX_BUF_SIZE = 1024 * 1024;
typedef std::array<uint8_t, RX_BUF_SIZE> byte_array_t;
typedef std::unique_ptr<byte_array_t> unique_byte_array_t;
unique_byte_array_t rx_buf;
srslte_netsource_t net_source;
srslte::log* log = nullptr;
};
#endif // SRSLTE_NETSOURE_HANDLER_H

@ -29,7 +29,7 @@
#define MAC_LTE_DLT 147
#define NAS_LTE_DLT 148
#define RLC_LTE_DLT 149 // UDP needs to be selected as protocol
#define UDP_DLT 149 // UDP needs to be selected as protocol
#define S1AP_LTE_DLT 150
/* This structure gets written to the start of the file */
@ -102,6 +102,25 @@ typedef struct NAS_Context_Info_s {
// No Context yet
} NAS_Context_Info_t;
#define MAC_NR_START_STRING "mac-nr"
#define MAC_NR_PHR_TYPE2_OTHERCELL_TAG 0x05
#define MAC_NR_HARQID 0x06
/* Context information for every MAC NR PDU that will be logged */
typedef struct {
uint8_t radioType;
uint8_t direction;
uint8_t rntiType;
uint16_t rnti;
uint16_t ueid;
uint8_t harqid;
uint8_t phr_type2_othercell;
uint16_t system_frame_number;
uint8_t sub_frame_number;
uint16_t length;
} mac_nr_context_info_t;
/* RLC-LTE disector */
@ -437,4 +456,93 @@ inline int LTE_PCAP_S1AP_WritePDU(FILE *fd, S1AP_Context_Info_t *context,
return 1;
}
/**************************************************************************
* API functions for writing MAC-NR PCAP files *
**************************************************************************/
/* Write an individual NR MAC PDU (PCAP packet header + UDP header + nr-mac-context + mac-pdu) */
inline int NR_PCAP_MAC_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length)
{
char context_header[256] = {};
int offset = 0;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return 0;
}
// Add dummy UDP header, start with src and dest port
context_header[offset++] = 0xde;
context_header[offset++] = 0xad;
context_header[offset++] = 0xbe;
context_header[offset++] = 0xef;
// length
uint16_t tmp16 = htons(length + 31);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
// dummy CRC
context_header[offset++] = 0xde;
context_header[offset++] = 0xad;
// Start magic string
memcpy(&context_header[offset], MAC_NR_START_STRING, strlen(MAC_NR_START_STRING));
offset += strlen(MAC_NR_START_STRING);
/*****************************************************************/
/* Context information (same as written by UDP heuristic clients */
context_header[offset++] = context->radioType;
context_header[offset++] = context->direction;
context_header[offset++] = context->rntiType;
/* RNTI */
context_header[offset++] = MAC_LTE_RNTI_TAG;
tmp16 = htons(context->rnti);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
/* UEId */
context_header[offset++] = MAC_LTE_UEID_TAG;
tmp16 = htons(context->ueid);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
/* HARQID */
context_header[offset++] = MAC_NR_HARQID;
context_header[offset++] = context->harqid;
/* PHR Type2 other cell */
context_header[offset++] = MAC_NR_PHR_TYPE2_OTHERCELL_TAG;
context_header[offset++] = context->phr_type2_othercell;
/* Subframe Number and System Frame Number */
/* SFN is stored in 12 MSB and SF in 4 LSB */
context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
tmp16 = (context->system_frame_number << 4) | context->sub_frame_number;
tmp16 = htons(tmp16);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
/* Data tag immediately preceding PDU */
context_header[offset++] = MAC_LTE_PAYLOAD_TAG;
/****************************************************************/
/* PCAP Header */
struct timeval t;
gettimeofday(&t, NULL);
pcaprec_hdr_t packet_header;
packet_header.ts_sec = t.tv_sec;
packet_header.ts_usec = t.tv_usec;
packet_header.incl_len = offset + length;
packet_header.orig_len = offset + length;
/***************************************************************/
/* Now write everything to the file */
fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd);
fwrite(context_header, 1, offset, fd);
fwrite(PDU, 1, length, fd);
return 1;
}
#endif // SRSLTE_PCAP_H

@ -136,7 +136,16 @@ public:
ret = subheaders[nof_subheaders].read_subheader(&ptr);
nof_subheaders++;
}
} while (ret && (nof_subheaders + 1) < (int)max_subheaders);
if (ret && (ptr - init_ptr) >= pdu_len) {
// stop processing last subheader indicates another one but all bytes are consume
nof_subheaders = 0;
INFO("Corrupted MAC PDU - all bytes have been consumed (pdu_len=%d)\n", pdu_len);
if (log) {
log->info_hex(init_ptr, pdu_len, "Corrupted MAC PDU - all bytes have been consumed (pdu_len=%d)\n", pdu_len);
}
}
} while (ret && (nof_subheaders + 1) < (int)max_subheaders && pdu_len > (ptr - init_ptr));
for (int i = 0; i < nof_subheaders; i++) {
subheaders[i].read_payload(&ptr);

@ -55,6 +55,6 @@ private:
uint16_t channel_id);
};
} // namespace srsue
} // namespace srslte
#endif // RLCPCAP_H

@ -29,36 +29,38 @@
#include "srslte/common/common.h"
#define SECURITY_DIRECTION_UPLINK 0
#define SECURITY_DIRECTION_DOWNLINK 1
namespace srslte {
typedef enum{
CIPHERING_ALGORITHM_ID_EEA0 = 0,
CIPHERING_ALGORITHM_ID_128_EEA1,
CIPHERING_ALGORITHM_ID_128_EEA2,
CIPHERING_ALGORITHM_ID_N_ITEMS,
}CIPHERING_ALGORITHM_ID_ENUM;
static const char ciphering_algorithm_id_text[CIPHERING_ALGORITHM_ID_N_ITEMS][20] = {"EEA0",
"128-EEA1",
"128-EEA2"};
typedef enum{
INTEGRITY_ALGORITHM_ID_EIA0 = 0,
INTEGRITY_ALGORITHM_ID_128_EIA1,
INTEGRITY_ALGORITHM_ID_128_EIA2,
INTEGRITY_ALGORITHM_ID_N_ITEMS,
}INTEGRITY_ALGORITHM_ID_ENUM;
static const char integrity_algorithm_id_text[INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {"EIA0",
"128-EIA1",
"128-EIA2"};
typedef enum {
CIPHERING_ALGORITHM_ID_EEA0 = 0,
CIPHERING_ALGORITHM_ID_128_EEA1,
CIPHERING_ALGORITHM_ID_128_EEA2,
CIPHERING_ALGORITHM_ID_128_EEA3,
CIPHERING_ALGORITHM_ID_N_ITEMS,
} CIPHERING_ALGORITHM_ID_ENUM;
static const char ciphering_algorithm_id_text[CIPHERING_ALGORITHM_ID_N_ITEMS][20] = {
"EEA0", "128-EEA1", "128-EEA2", "128-EEA3"};
typedef enum {
INTEGRITY_ALGORITHM_ID_EIA0 = 0,
INTEGRITY_ALGORITHM_ID_128_EIA1,
INTEGRITY_ALGORITHM_ID_128_EIA2,
INTEGRITY_ALGORITHM_ID_128_EIA3,
INTEGRITY_ALGORITHM_ID_N_ITEMS,
} INTEGRITY_ALGORITHM_ID_ENUM;
static const char integrity_algorithm_id_text[INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {
"EIA0", "128-EIA1", "128-EIA2", "128-EIA3"};
typedef enum {
SECURITY_DIRECTION_UPLINK = 0,
SECURITY_DIRECTION_DOWNLINK = 1,
SECURITY_DIRECTION_N_ITEMS,
} security_direction_t;
static const char security_direction_text[INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {"Uplink", "Downlink"};
/******************************************************************************
* Key Generation
*****************************************************************************/
uint8_t security_generate_k_asme( uint8_t *ck,
uint8_t *ik,
uint8_t *ak,
@ -101,83 +103,45 @@ uint8_t security_generate_k_up( uint8_t *k_enb,
/******************************************************************************
* Integrity Protection
*****************************************************************************/
uint8_t security_128_eia1(
uint8_t* key, uint32_t count, uint32_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac);
uint8_t security_128_eia1( uint8_t *key,
uint32_t count,
uint32_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *mac);
uint8_t security_128_eia2(
uint8_t* key, uint32_t count, uint32_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac);
uint8_t security_128_eia2( uint8_t *key,
uint32_t count,
uint32_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *mac);
uint8_t security_md5(const uint8_t *input,
size_t len,
uint8_t *output);
uint8_t security_128_eia3(
uint8_t* key, uint32_t count, uint32_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac);
uint8_t security_md5(const uint8_t* input, size_t len, uint8_t* output);
/******************************************************************************
* Encryption / Decryption
*****************************************************************************/
uint8_t security_128_eea1(
uint8_t* key, uint32_t count, uint8_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* msg_out);
uint8_t security_128_eea2(
uint8_t* key, uint32_t count, uint8_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* msg_out);
uint8_t security_128_eea1( uint8_t *key,
uint32_t count,
uint8_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *msg_out);
uint8_t security_128_eea2(uint8_t *key,
uint32_t count,
uint8_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *msg_out);
uint8_t security_128_eea3(
uint8_t* key, uint32_t count, uint8_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* msg_out);
/******************************************************************************
* Authentication
*****************************************************************************/
uint8_t compute_opc( uint8_t *k,
uint8_t *op,
uint8_t *opc);
uint8_t security_milenage_f1( uint8_t *k,
uint8_t *op,
uint8_t *rand,
uint8_t *sqn,
uint8_t *amf,
uint8_t *mac_a);
uint8_t security_milenage_f1_star( uint8_t *k,
uint8_t *op,
uint8_t *rand,
uint8_t *sqn,
uint8_t *amf,
uint8_t *mac_s);
uint8_t security_milenage_f2345( uint8_t *k,
uint8_t *op,
uint8_t *rand,
uint8_t *res,
uint8_t *ck,
uint8_t *ik,
uint8_t *ak);
uint8_t compute_opc(uint8_t* k, uint8_t* op, uint8_t* opc);
uint8_t security_milenage_f1(uint8_t* k, uint8_t* op, uint8_t* rand, uint8_t* sqn, uint8_t* amf, uint8_t* mac_a);
uint8_t security_milenage_f1_star(uint8_t* k, uint8_t* op, uint8_t* rand, uint8_t* sqn, uint8_t* amf, uint8_t* mac_s);
uint8_t
security_milenage_f2345(uint8_t* k, uint8_t* op, uint8_t* rand, uint8_t* res, uint8_t* ck, uint8_t* ik, uint8_t* ak);
uint8_t security_milenage_f5_star( uint8_t *k,
uint8_t *op,
uint8_t *rand,
uint8_t *ak);
} // namespace srslte
#endif // SRSLTE_SECURITY_H

@ -0,0 +1,317 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#ifndef SRSLTE_RESUMABLE_PROCEDURES_H
#define SRSLTE_RESUMABLE_PROCEDURES_H
namespace srslte {
enum class proc_state_t { on_going, success, error, inactive };
enum class proc_outcome_t { repeat, yield, success, error };
/**************************************************************************************
* class: proc_impl_t
* Provides an polymorphic interface for resumable procedures. This base can then be used
* by a task dispatch queue via the method "run()".
* Every procedure starts in inactive state, and finishes with success or error.
* With methods:
* - run() - executes a procedure, returning true if the procedure is still running
* or false, if it has completed
* - step() - method overriden by child class that will be called by run(). step()
* executes a procedure "action" based on its current internal state,
* and return a proc_outcome_t variable with possible values:
* - yield - the procedure performed the action but hasn't completed yet.
* - repeat - the same as yield, but explicitly asking that run() should
* recall step() again (probably the procedure state has changed)
* - error - the procedure has finished unsuccessfully
* - success - the procedure has completed successfully
* - stop() - called automatically when a procedure has finished. Useful for actions
* upon procedure completion, like sending back a response.
* - set_proc_state() / is_#() - setter and getters for current procedure state
************************************************************************************/
class proc_impl_t
{
public:
proc_impl_t() : proc_state(proc_state_t::inactive) {}
virtual ~proc_impl_t() = default;
virtual proc_outcome_t step() = 0;
virtual void stop() {} // may be overloaded
bool run()
{
proc_outcome_t outcome = proc_outcome_t::repeat;
while (is_running() and outcome == proc_outcome_t::repeat) {
outcome = step();
if (outcome == proc_outcome_t::error) {
set_proc_state(proc_state_t::error);
} else if (outcome == proc_outcome_t::success) {
set_proc_state(proc_state_t::success);
}
}
return is_running();
}
void set_proc_state(proc_state_t new_state)
{
proc_state = new_state;
if (proc_state == proc_state_t::error or proc_state == proc_state_t::success) {
stop();
}
}
bool is_error() const { return proc_state == proc_state_t::error; }
bool is_success() const { return proc_state == proc_state_t::success; }
bool is_running() const { return proc_state == proc_state_t::on_going; }
bool is_complete() const { return is_success() or is_error(); }
bool is_active() const { return proc_state != proc_state_t::inactive; }
private:
proc_state_t proc_state;
};
/**************************************************************************************
* class: proc_t<T>
* Handles the lifetime, of a procedure T that derives from proc_impl_t, including
* its alloc, initialization, and reset back to initial state once the procedure has been
* completed and the user has extracted its results.
* Can only be re-launched when a procedure T becomes inactive.
* It uses a unique_ptr<T> to allow the use of procedures that are forward declared.
* It provides the following methods:
* - run() - calls proc_impl_t::run(). See above.
* - launch() - initializes the procedure T by calling T::init(...). Handles the case
* of failed initialization, and forbids the initialization of procedures
* that are already active.
* - pop() - extracts the result of the procedure if it has finished, and sets
* proc_t<T> back to inactive
* - trigger_event(Event) - used for handling external events. The procedure T will
* have to define a method "trigger_event(Event)" as well,
* specifying how each event type should be handled.
************************************************************************************/
template <class T>
class proc_t
{
public:
explicit proc_t() : proc_impl_ptr(new T()) {}
T* get() { return proc_impl_ptr.get(); }
bool is_active() const { return proc_impl_ptr->is_active(); }
bool is_complete() const { return proc_impl_ptr->is_complete(); }
T* release() { return proc_impl_ptr.release(); }
bool run() { return proc_impl_ptr->run(); }
void clear()
{
// Destructs the current object, and calls default ctor (which sets proc back to inactive and ready for another run)
proc_impl_ptr->~T();
new (proc_impl_ptr.get()) T();
}
template <class Event>
void trigger_event(Event&& e)
{
if (proc_impl_ptr->is_running()) {
proc_outcome_t outcome = proc_impl_ptr->trigger_event(std::forward<Event>(e));
if (outcome == proc_outcome_t::error) {
proc_impl_ptr->set_proc_state(proc_state_t::error);
} else if (outcome == proc_outcome_t::success) {
proc_impl_ptr->set_proc_state(proc_state_t::success);
}
}
}
T pop()
{
if (not proc_impl_ptr->is_complete()) {
return T();
}
T ret(std::move(*proc_impl_ptr));
clear();
return ret;
}
template <class... Args>
bool launch(Args&&... args)
{
if (is_active()) {
// if already active
return false;
}
proc_impl_ptr->set_proc_state(proc_state_t::on_going);
proc_outcome_t init_ret = proc_impl_ptr->init(std::forward<Args>(args)...);
switch (init_ret) {
case proc_outcome_t::error:
proc_impl_ptr->set_proc_state(proc_state_t::error); // call stop as an error
clear();
return false;
case proc_outcome_t::success:
proc_impl_ptr->set_proc_state(proc_state_t::success);
break;
case proc_outcome_t::repeat:
run(); // call run right away
break;
case proc_outcome_t::yield:
break;
}
return true;
}
private:
std::unique_ptr<T> proc_impl_ptr;
};
/**************************************************************************************
* class: func_proc_t
* A proc_impl_t used to store lambda functions and other function pointers as a step()
* method, avoiding this way, always having to create a new class per procedure.
************************************************************************************/
class func_proc_t : public proc_impl_t
{
public:
proc_outcome_t init(std::function<proc_outcome_t()> step_func_)
{
step_func = std::move(step_func_);
return proc_outcome_t::yield;
}
proc_outcome_t step() final { return step_func(); }
private:
std::function<proc_outcome_t()> step_func;
};
/**************************************************************************************
* class: func_proc_t
* A helper proc_impl_t whose step()/stop() are no op, but has a trigger_event() that
* signals that the method has finished and store a result of type OutcomeType.
************************************************************************************/
template <class OutcomeType>
class query_proc_t : public proc_impl_t
{
public:
proc_outcome_t init() { return proc_outcome_t::yield; }
proc_outcome_t step() final { return proc_outcome_t::yield; }
proc_outcome_t trigger_event(const OutcomeType& outcome_)
{
outcome = outcome_;
return proc_outcome_t::success;
}
const OutcomeType& result() const { return outcome; }
private:
OutcomeType outcome;
};
/**************************************************************************************
* class: callback_list_t
* Stores procedures that derive from proc_impl_t. Its run() method calls sequentially
* all the stored procedures run() method, and removes the procedures if they have
* completed.
* There are different ways to add a procedure to the list:
* - add_proc(...) - adds a proc_t<T>, and once the procedure has completed, takes it
* out of the container without resetting it back to its initial state
* or deleting. This is useful, if the user wants to extract the
* procedure result via proc_t<T>::pop()
* - consume_proc(...) - receives a proc_t<T> as a rvalue, and calls the proc_t<T>
* destructor once the procedure has ended. Useful, for procedures
* for which the user is not interested in the result, or reusing
* - defer_proc(...) - same as add_proc(...), but once the procedure has finished, it
* automatically sets the procedure back to its initial state.
* Useful if the user is not interested in handling the result
* - defer_task(...) - same as consume_proc(...) but takes a function pointer that
* specifies a proc_impl_t step() function
************************************************************************************/
class callback_list_t
{
public:
typedef std::function<void(proc_impl_t*)> proc_deleter_t;
typedef std::unique_ptr<proc_impl_t, proc_deleter_t> callback_obj_t;
template <class T>
struct recycle_deleter_t {
void operator()(proc_impl_t* p)
{
if (p != nullptr) {
T* Tp = static_cast<T*>(p);
Tp->~T();
new (Tp) T();
}
}
};
template <class T>
void add_proc(proc_t<T>& proc)
{
if (proc.is_complete()) {
return;
}
callback_obj_t ptr(proc.get(), [](proc_impl_t* p) { /* do nothing */ });
callbacks.push_back(std::move(ptr));
}
template <class T>
void consume_proc(proc_t<T>&& proc)
{
if (proc.is_complete()) {
return;
}
callback_obj_t ptr(proc.release(), std::default_delete<proc_impl_t>());
callbacks.push_back(std::move(ptr));
}
template <class T>
void defer_proc(proc_t<T>& proc)
{
if (proc.is_complete()) {
proc.pop();
return;
}
callback_obj_t ptr(proc.get(), recycle_deleter_t<T>());
callbacks.push_back(std::move(ptr));
}
bool defer_task(std::function<proc_outcome_t()> step_func)
{
proc_t<func_proc_t> proc;
if (not proc.launch(std::move(step_func))) {
return false;
}
consume_proc(std::move(proc));
return true;
}
void run()
{
// Calls run for all callbacks. Remove the ones that have finished. The proc dtor is called.
callbacks.remove_if([](callback_obj_t& elem) { return not elem->run(); });
}
size_t size() const { return callbacks.size(); }
private:
std::list<callback_obj_t> callbacks;
};
} // namespace srslte
#endif // SRSLTE_RESUMABLE_PROCEDURES_H

@ -29,10 +29,15 @@
#ifndef SRSLTE_THREAD_POOL_H
#define SRSLTE_THREAD_POOL_H
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <stack>
#include <stdint.h>
#include <string>
#include <vector>
#include <stack>
#include "srslte/common/threads.h"
@ -94,8 +99,50 @@ private:
std::vector<worker_status> status;
std::vector<pthread_cond_t> cvar;
std::vector<pthread_mutex_t> mutex;
std::stack<worker*> available_workers;
std::stack<worker*> available_workers;
};
}
class task_thread_pool
{
using task_t = std::function<void(uint32_t worker_id)>;
public:
explicit task_thread_pool(uint32_t nof_workers);
~task_thread_pool();
void start(int32_t prio = -1, uint32_t mask = 255);
void stop();
void push_task(const task_t& task);
void push_task(task_t&& task);
uint32_t nof_pending_tasks();
private:
class worker_t : public thread
{
public:
explicit worker_t(task_thread_pool* parent_, uint32_t id);
void stop();
void setup(int32_t prio, uint32_t mask);
bool is_running() const { return running; }
uint32_t id() const { return id_; }
void run_thread() override;
private:
bool wait_task(task_t* task);
task_thread_pool* parent = nullptr;
uint32_t id_ = 0;
bool running = false;
};
std::queue<task_t> pending_tasks;
std::vector<worker_t> workers;
std::mutex queue_mutex;
std::condition_variable cv_empty;
bool running;
};
} // namespace srslte
#endif // SRSLTE_THREAD_POOL_H

@ -50,9 +50,11 @@ class thread
{
public:
thread(const std::string& name_) : _thread(0), name(name_) {}
bool start(int prio = -1) {
return threads_new_rt_prio(&_thread, thread_function_entry, this, prio);
}
thread(const thread&) = delete;
thread(thread&&) noexcept = default;
thread& operator=(const thread&) = delete;
thread& operator=(thread&&) noexcept = default;
bool start(int prio = -1) { return threads_new_rt_prio(&_thread, thread_function_entry, this, prio); }
bool start_cpu(int prio, int cpu) {
return threads_new_rt_cpu(&_thread, thread_function_entry, this, cpu, prio);
}

@ -92,20 +92,21 @@ public:
private:
timer_callback *callback;
uint32_t timeout;
uint32_t counter;
bool running;
uint32_t counter;
bool running;
};
timers(uint32_t nof_timers_) : timer_list(nof_timers_),used_timers(nof_timers_) {
nof_timers = nof_timers_;
next_timer = 0;
timers(uint32_t nof_timers_) : timer_list(nof_timers_), used_timers(nof_timers_)
{
nof_timers = nof_timers_;
next_timer = 0;
nof_used_timers = 0;
for (uint32_t i=0;i<nof_timers;i++) {
for (uint32_t i = 0; i < nof_timers; i++) {
timer_list[i].id = i;
used_timers[i] = false;
}
}
void step_all() {
for (uint32_t i=0;i<nof_timers;i++) {
get(i)->step();
@ -169,5 +170,5 @@ private:
};
} // namespace srslte
#endif // SRSLTE_TIMERS_H

@ -68,8 +68,8 @@ class tti_sync
uint32_t modulus;
uint32_t producer_cntr;
uint32_t consumer_cntr;
};
};
} // namespace srsue
} // namespace srslte
#endif // SRSLTE_TTI_SYNC_H

@ -0,0 +1,48 @@
/*---------------------------------------------------------
zuc.h
Adapted from ETSI/SAGE specifications:
"Specification of the 3GPP Confidentiality
and Integrity Algorithms 128-EEA3 & 128-EIA3.
Document 2: ZUC Specification"
---------------------------------------------------------*/
#ifndef SRSLTE_ZUC_H
#define SRSLTE_ZUC_H
typedef unsigned char u8;
typedef unsigned int u32;
/* the state registers of LFSR */
typedef struct {
u32 LFSR_S0;
u32 LFSR_S1;
u32 LFSR_S2;
u32 LFSR_S3;
u32 LFSR_S4;
u32 LFSR_S5;
u32 LFSR_S6;
u32 LFSR_S7;
u32 LFSR_S8;
u32 LFSR_S9;
u32 LFSR_S10;
u32 LFSR_S11;
u32 LFSR_S12;
u32 LFSR_S13;
u32 LFSR_S14;
u32 LFSR_S15;
/* the registers of F */
u32 F_R1;
u32 F_R2;
/* the outputs of BitReorganization */
u32 BRC_X0;
u32 BRC_X1;
u32 BRC_X2;
u32 BRC_X3;
} zuc_state_t;
void zuc_initialize(zuc_state_t* state, u8* k, u8* iv);
void zuc_generate_keystream(zuc_state_t* state, int key_stream_len, u32* p_keystream);
#endif // SRSLTE_ZUC_H

@ -57,17 +57,18 @@ public:
virtual void set_rx_srate(const uint32_t& radio_idx, const double& srate) = 0;
// getter
virtual float get_rx_gain(const uint32_t& radio_idx) = 0;
virtual double get_freq_offset() = 0;
virtual double get_tx_freq(const uint32_t& radio_idx) = 0;
virtual double get_rx_freq(const uint32_t& radio_idx) = 0;
virtual float get_max_tx_power() = 0;
virtual float get_tx_gain_offset() = 0;
virtual float get_rx_gain_offset() = 0;
virtual bool is_continuous_tx() = 0;
virtual bool is_init() = 0;
virtual void reset() = 0;
virtual srslte_rf_info_t* get_info(const uint32_t& radio_idx) = 0;
virtual float get_rx_gain(const uint32_t& radio_idx) = 0;
virtual double get_freq_offset() = 0;
virtual double get_tx_freq(const uint32_t& radio_idx) = 0;
virtual double get_rx_freq(const uint32_t& radio_idx) = 0;
virtual float get_max_tx_power() = 0;
virtual float get_tx_gain_offset() = 0;
virtual float get_rx_gain_offset() = 0;
virtual bool is_continuous_tx() = 0;
virtual bool get_is_start_of_burst(const uint32_t& radio_idx) = 0;
virtual bool is_init() = 0;
virtual void reset() = 0;
virtual srslte_rf_info_t* get_info(const uint32_t& radio_idx) = 0;
};
class phy_interface_radio

@ -194,6 +194,7 @@ public:
virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::rlc_config_t cnfg) = 0;
virtual void add_bearer_mrb(uint16_t rnti, uint32_t lcid) = 0;
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual bool has_bearer(uint16_t rnti, uint32_t lcid) = 0;
};
// PDCP interface for GTPU
@ -207,20 +208,20 @@ public:
class pdcp_interface_rrc
{
public:
virtual void reset(uint16_t rnti) = 0;
virtual void add_user(uint16_t rnti) = 0;
virtual void rem_user(uint16_t rnti) = 0;
virtual void reset(uint16_t rnti) = 0;
virtual void add_user(uint16_t rnti) = 0;
virtual void rem_user(uint16_t rnti) = 0;
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cnfg) = 0;
virtual void config_security(uint16_t rnti,
uint32_t lcid,
uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
uint8_t *k_up_enc_,
virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::pdcp_config_t cnfg) = 0;
virtual void config_security(uint16_t rnti,
uint32_t lcid,
uint8_t* k_rrc_enc_,
uint8_t* k_rrc_int_,
uint8_t* k_up_enc_,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void enable_integrity(uint16_t rnti, uint32_t lcid) = 0;
virtual void enable_encryption(uint16_t rnti, uint32_t lcid) = 0;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void enable_integrity(uint16_t rnti, uint32_t lcid) = 0;
virtual void enable_encryption(uint16_t rnti, uint32_t lcid) = 0;
};
// PDCP interface for RLC

@ -24,6 +24,7 @@
#include "srslte/common/bcd_helpers.h"
#include "srslte/config.h"
#include "srslte/srslte.h"
#include <string>
/************************
@ -124,6 +125,7 @@ struct plmn_id_t {
struct s_tmsi_t {
uint8_t mmec = 0;
uint32_t m_tmsi = 0;
bool operator==(const s_tmsi_t& other) const { return mmec == other.mmec and m_tmsi == other.m_tmsi; }
};
/***************************
@ -180,6 +182,18 @@ inline uint16_t to_number(const rlc_umd_sn_size_t& sn_size)
return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size);
}
enum class rlc_um_nr_sn_size_t { size6bits, size12bits, nulltype };
inline std::string to_string(const rlc_um_nr_sn_size_t& sn_size)
{
constexpr static const char* options[] = {"6 bits", "12 bits"};
return enum_to_text(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size);
}
inline uint16_t to_number(const rlc_um_nr_sn_size_t& sn_size)
{
constexpr static uint16_t options[] = {6, 12};
return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size);
}
struct rlc_am_config_t {
/****************************************************************************
* Configurable parameters
@ -213,22 +227,49 @@ struct rlc_um_config_t {
bool is_mrb; // Whether this is a multicast bearer
};
struct rlc_um_nr_config_t {
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 38.322 v15.3.0 Section 7
***************************************************************************/
rlc_um_nr_sn_size_t sn_field_length; // Number of bits used for sequence number
uint32_t UM_Window_Size;
uint32_t mod; // Rx/Tx counter modulus
};
#define RLC_TX_QUEUE_LEN (128)
enum class rlc_type_t { lte, nr, nulltype };
inline std::string to_string(const rlc_type_t& type)
{
constexpr static const char* options[] = {"LTE", "NR"};
return enum_to_text(options, (uint32_t)rlc_type_t::nulltype, (uint32_t)type);
}
class rlc_config_t
{
public:
rlc_type_t type;
rlc_mode_t rlc_mode;
rlc_am_config_t am;
rlc_um_config_t um;
rlc_um_nr_config_t um_nr;
uint32_t tx_queue_length;
rlc_config_t() : rlc_mode(rlc_mode_t::tm), am(), um(), tx_queue_length(RLC_TX_QUEUE_LEN){};
rlc_config_t() :
type(rlc_type_t::lte),
rlc_mode(rlc_mode_t::tm),
am(),
um(),
um_nr(),
tx_queue_length(RLC_TX_QUEUE_LEN){};
// Factory for MCH
static rlc_config_t mch_config()
{
rlc_config_t cfg;
rlc_config_t cfg = {};
cfg.type = rlc_type_t::lte;
cfg.rlc_mode = rlc_mode_t::um;
cfg.um.t_reordering = 45;
cfg.um.rx_sn_field_length = rlc_umd_sn_size_t::size5bits;
@ -246,7 +287,8 @@ public:
return {};
}
// SRB1 and SRB2 are AM
rlc_config_t rlc_cfg;
rlc_config_t rlc_cfg = {};
rlc_cfg.type = rlc_type_t::lte;
rlc_cfg.rlc_mode = rlc_mode_t::am;
rlc_cfg.am.t_poll_retx = 45;
rlc_cfg.am.poll_pdu = -1;
@ -258,7 +300,8 @@ public:
}
static rlc_config_t default_rlc_um_config(uint32_t sn_size = 10)
{
rlc_config_t cnfg;
rlc_config_t cnfg = {};
cnfg.type = rlc_type_t::lte;
cnfg.rlc_mode = rlc_mode_t::um;
cnfg.um.t_reordering = 5;
if (sn_size == 10) {
@ -280,7 +323,8 @@ public:
}
static rlc_config_t default_rlc_am_config()
{
rlc_config_t rlc_cnfg;
rlc_config_t rlc_cnfg = {};
rlc_cnfg.type = rlc_type_t::lte;
rlc_cnfg.rlc_mode = rlc_mode_t::am;
rlc_cnfg.am.t_reordering = 5;
rlc_cnfg.am.t_status_prohibit = 5;
@ -290,7 +334,306 @@ public:
rlc_cnfg.am.t_poll_retx = 5;
return rlc_cnfg;
}
static rlc_config_t default_rlc_um_nr_config(uint32_t sn_size = 6)
{
rlc_config_t cnfg = {};
cnfg.type = rlc_type_t::nr;
cnfg.rlc_mode = rlc_mode_t::um;
if (sn_size == 6) {
cnfg.um_nr.sn_field_length = rlc_um_nr_sn_size_t::size6bits;
cnfg.um_nr.UM_Window_Size = 32;
cnfg.um_nr.mod = 64;
} else if (sn_size == 12) {
cnfg.um_nr.sn_field_length = rlc_um_nr_sn_size_t::size12bits;
cnfg.um_nr.UM_Window_Size = 2048;
cnfg.um_nr.mod = 64;
} else {
return {};
}
return cnfg;
}
};
/***************************
* MAC Config
**************************/
struct bsr_cfg_t {
int periodic_timer;
int retx_timer;
bsr_cfg_t() { reset(); }
void reset()
{
periodic_timer = -1;
retx_timer = 2560;
}
};
struct phr_cfg_t {
bool enabled;
int periodic_timer;
int prohibit_timer;
int db_pathloss_change;
bool extended;
phr_cfg_t() { reset(); }
void reset()
{
enabled = false;
periodic_timer = -1;
prohibit_timer = -1;
db_pathloss_change = -1;
extended = false;
}
};
struct sr_cfg_t {
bool enabled;
int dsr_transmax;
sr_cfg_t() { reset(); }
void reset()
{
enabled = false;
dsr_transmax = 0;
}
};
struct ul_harq_cfg_t {
uint32_t max_harq_msg3_tx;
uint32_t max_harq_tx;
ul_harq_cfg_t() { reset(); }
void reset()
{
max_harq_msg3_tx = 5;
max_harq_tx = 5;
}
};
struct rach_cfg_t {
bool enabled;
uint32_t nof_preambles;
uint32_t nof_groupA_preambles;
int32_t messagePowerOffsetGroupB;
uint32_t messageSizeGroupA;
uint32_t responseWindowSize;
uint32_t powerRampingStep;
uint32_t preambleTransMax;
int32_t iniReceivedTargetPower;
uint32_t contentionResolutionTimer;
uint32_t new_ra_msg_len;
rach_cfg_t() { reset(); }
void reset()
{
enabled = false;
nof_preambles = 0;
nof_groupA_preambles = 0;
messagePowerOffsetGroupB = 0;
messageSizeGroupA = 0;
responseWindowSize = 0;
powerRampingStep = 0;
preambleTransMax = 0;
iniReceivedTargetPower = 0;
contentionResolutionTimer = 0;
new_ra_msg_len = 0;
}
};
struct mac_cfg_t {
// Default constructor with default values as in 36.331 9.2.2
mac_cfg_t() { set_defaults(); }
void set_defaults()
{
rach_cfg.reset();
set_mac_main_cfg_default();
}
void set_mac_main_cfg_default()
{
bsr_cfg.reset();
phr_cfg.reset();
sr_cfg.reset();
harq_cfg.reset();
time_alignment_timer = -1;
}
bsr_cfg_t bsr_cfg;
phr_cfg_t phr_cfg;
sr_cfg_t sr_cfg;
rach_cfg_t rach_cfg;
ul_harq_cfg_t harq_cfg;
int time_alignment_timer;
};
/***************************
* PHY Config
**************************/
struct phy_cfg_t {
phy_cfg_t() { set_defaults(); }
void set_defaults()
{
ZERO_OBJECT(ul_cfg);
ZERO_OBJECT(dl_cfg);
ZERO_OBJECT(prach_cfg);
// CommonConfig defaults for non-zero values
ul_cfg.pucch.delta_pucch_shift = 1;
ul_cfg.power_ctrl.delta_f_pucch[0] = 0;
ul_cfg.power_ctrl.delta_f_pucch[1] = 1;
ul_cfg.power_ctrl.delta_f_pucch[2] = 0;
ul_cfg.power_ctrl.delta_f_pucch[3] = 0;
ul_cfg.power_ctrl.delta_f_pucch[4] = 0;
set_defaults_dedicated();
}
// 36.331 9.2.4
void set_defaults_dedicated()
{
dl_cfg.tm = SRSLTE_TM1;
dl_cfg.pdsch.use_tbs_index_alt = false;
dl_cfg.pdsch.p_a = 0;
dl_cfg.cqi_report.periodic_configured = false;
dl_cfg.cqi_report.aperiodic_configured = false;
ul_cfg.pucch.tdd_ack_multiplex = false;
ul_cfg.pusch.uci_offset.I_offset_ack = 10;
ul_cfg.pusch.uci_offset.I_offset_ri = 12;
ul_cfg.pusch.uci_offset.I_offset_cqi = 15;
ul_cfg.power_ctrl.p0_nominal_pusch = 0;
ul_cfg.power_ctrl.delta_mcs_based = false;
ul_cfg.power_ctrl.acc_enabled = true;
ul_cfg.power_ctrl.p0_nominal_pucch = 0;
ul_cfg.power_ctrl.p_srs_offset = 7;
ul_cfg.srs.dedicated_enabled = false;
ul_cfg.pucch.sr_configured = false;
}
srslte_dl_cfg_t dl_cfg;
srslte_ul_cfg_t ul_cfg;
srslte_prach_cfg_t prach_cfg;
};
struct mbsfn_sf_cfg_t {
enum class alloc_period_t { n1, n2, n4, n8, n16, n32, nulltype };
alloc_period_t radioframe_alloc_period;
uint8_t radioframe_alloc_offset = 0;
enum class sf_alloc_type_t { one_frame, four_frames, nulltype };
sf_alloc_type_t nof_alloc_subfrs;
uint32_t sf_alloc;
};
inline uint16_t enum_to_number(const mbsfn_sf_cfg_t::alloc_period_t& radioframe_period)
{
constexpr static uint16_t options[] = {1, 2, 4, 8, 16, 32};
return enum_to_number(options, (uint32_t)mbsfn_sf_cfg_t::alloc_period_t::nulltype, (uint32_t)radioframe_period);
}
struct mbms_notif_cfg_t {
enum class coeff_t { n2, n4 };
coeff_t notif_repeat_coeff = coeff_t::n2;
uint8_t notif_offset = 0;
uint8_t notif_sf_idx = 1;
};
// MBSFN-AreaInfo-r9 ::= SEQUENCE
struct mbsfn_area_info_t {
uint8_t mbsfn_area_id = 0;
enum class region_len_t { s1, s2, nulltype } non_mbsfn_region_len;
uint8_t notif_ind = 0;
struct mcch_cfg_t {
enum class repeat_period_t { rf32, rf64, rf128, rf256, nulltype } mcch_repeat_period;
uint8_t mcch_offset = 0;
enum class mod_period_t { rf512, rf1024 } mcch_mod_period;
uint8_t sf_alloc_info = 0;
enum class sig_mcs_t { n2, n7, n13, n19, nulltype } sig_mcs;
} mcch_cfg;
};
inline uint16_t enum_to_number(const mbsfn_area_info_t::region_len_t& region_len)
{
constexpr static uint16_t options[] = {1, 2};
return enum_to_number(options, (uint32_t)mbsfn_area_info_t::region_len_t::nulltype, (uint32_t)region_len);
}
inline uint16_t enum_to_number(const mbsfn_area_info_t::mcch_cfg_t::repeat_period_t& repeat_period)
{
constexpr static uint16_t options[] = {32, 64, 128, 256};
return enum_to_number(
options, (uint32_t)mbsfn_area_info_t::mcch_cfg_t::repeat_period_t::nulltype, (uint32_t)repeat_period);
}
inline uint16_t enum_to_number(const mbsfn_area_info_t::mcch_cfg_t::sig_mcs_t& sig_mcs)
{
constexpr static uint16_t options[] = {2, 7, 13, 19};
return enum_to_number(options, (uint32_t)mbsfn_area_info_t::mcch_cfg_t::sig_mcs_t::nulltype, (uint32_t)sig_mcs);
}
// TMGI-r9
struct tmgi_t {
enum class plmn_id_type_t { plmn_idx, explicit_value } plmn_id_type;
union choice {
uint8_t plmn_idx;
plmn_id_t explicit_value;
choice() : plmn_idx(0) {}
} plmn_id;
uint8_t serviced_id[3];
tmgi_t() : plmn_id_type(plmn_id_type_t::plmn_idx) {}
};
struct pmch_info_t {
// pmch_cfg_t
uint16_t sf_alloc_end = 0;
uint8_t data_mcs = 0;
enum class mch_sched_period_t { rf8, rf16, rf32, rf64, rf128, rf256, rf512, rf1024, nulltype } mch_sched_period;
// mbms_session_info_list
struct mbms_session_info_t {
bool session_id_present = false;
tmgi_t tmgi;
uint8_t session_id;
uint8_t lc_ch_id = 0;
};
uint32_t nof_mbms_session_info;
static const uint32_t max_session_per_pmch = 29;
mbms_session_info_t mbms_session_info_list[max_session_per_pmch];
};
inline uint16_t enum_to_number(const pmch_info_t::mch_sched_period_t& mch_period)
{
constexpr static uint16_t options[] = {8, 16, 32, 64, 128, 256, 512, 1024};
return enum_to_number(options, (uint32_t)pmch_info_t::mch_sched_period_t::nulltype, (uint32_t)mch_period);
}
struct mcch_msg_t {
uint32_t nof_common_sf_alloc = 0;
mbsfn_sf_cfg_t common_sf_alloc[8];
enum class common_sf_alloc_period_t { rf4, rf8, rf16, rf32, rf64, rf128, rf256, nulltype } common_sf_alloc_period;
uint32_t nof_pmch_info;
pmch_info_t pmch_info_list[15];
// mbsfn_area_cfg_v930_ies non crit ext OPTIONAL
};
inline uint16_t enum_to_number(const mcch_msg_t::common_sf_alloc_period_t& alloc_period)
{
constexpr static uint16_t options[] = {4, 8, 16, 32, 64, 128, 256};
return enum_to_number(options, (uint32_t)mcch_msg_t::common_sf_alloc_period_t::nulltype, (uint32_t)alloc_period);
}
struct phy_cfg_mbsfn_t {
mbsfn_sf_cfg_t mbsfn_subfr_cnfg;
mbms_notif_cfg_t mbsfn_notification_cnfg;
mbsfn_area_info_t mbsfn_area_info;
mcch_msg_t mcch;
};
// SystemInformationBlockType13-r9
struct sib13_t {
static const uint32_t max_mbsfn_area = 8;
uint32_t nof_mbsfn_area_info = 0;
mbsfn_area_info_t mbsfn_area_info_list[max_mbsfn_area];
mbms_notif_cfg_t notif_cfg;
};
} // namespace srslte
#endif // SRSLTE_RRC_INTERFACE_TYPES_H

@ -32,10 +32,11 @@
#include "rrc_interface_types.h"
#include "srslte/asn1/liblte_mme.h"
#include "srslte/asn1/rrc_asn1.h"
#include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/common/security.h"
#include "srslte/common/stack_procedure.h"
#include "srslte/interfaces/rrc_interface_types.h"
#include "srslte/phy/channel/channel.h"
#include "srslte/phy/rf/rf.h"
@ -118,43 +119,6 @@ public:
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
};
// NAS interface for RRC
class nas_interface_rrc
{
public:
typedef enum {
BARRING_NONE = 0,
BARRING_MO_DATA,
BARRING_MO_SIGNALLING,
BARRING_MT,
BARRING_ALL
} barring_t;
virtual void leave_connected() = 0;
virtual void set_barring(barring_t barring) = 0;
virtual void paging(srslte::s_tmsi_t* ue_identity) = 0;
virtual bool is_attached() = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual uint32_t get_k_enb_count() = 0;
virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0;
virtual uint32_t get_ipv4_addr() = 0;
virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0;
};
// NAS interface for UE
class nas_interface_ue
{
public:
virtual bool attach_request() = 0;
virtual bool detach_request() = 0;
};
// NAS interface for UE
class nas_interface_gw
{
public:
virtual bool attach_request() = 0;
};
// RRC interface for MAC
class rrc_interface_mac_common
{
@ -193,12 +157,13 @@ public:
virtual uint16_t get_mcc() = 0;
virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 0;
virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0;
virtual bool plmn_search() = 0;
virtual void plmn_select(srslte::plmn_id_t plmn_id) = 0;
virtual bool connection_request(srslte::establishment_cause_t cause,
srslte::unique_byte_buffer_t dedicatedInfoNAS) = 0;
virtual void set_ue_identity(srslte::s_tmsi_t s_tmsi) = 0;
virtual bool is_connected() = 0;
virtual void paging_completed(bool outcome) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0;
};
@ -212,44 +177,69 @@ public:
virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
};
// RRC interface for RLC
class rrc_interface_rlc
{
public:
virtual void max_retx_attempted() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual void max_retx_attempted() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
};
// NAS interface for RRC
class nas_interface_rrc
{
public:
typedef enum { BARRING_NONE = 0, BARRING_MO_DATA, BARRING_MO_SIGNALLING, BARRING_MT, BARRING_ALL } barring_t;
virtual void left_rrc_connected() = 0;
virtual void set_barring(barring_t barring) = 0;
virtual void paging(srslte::s_tmsi_t* ue_identity) = 0;
virtual bool is_attached() = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual uint32_t get_k_enb_count() = 0;
virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0;
virtual uint32_t get_ipv4_addr() = 0;
virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0;
virtual void plmn_search_completed(rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS],
int nof_plmns) = 0;
virtual bool connection_request_completed(bool outcome) = 0;
virtual void run_tti(uint32_t tti) = 0;
};
// NAS interface for UE
class nas_interface_ue
{
public:
virtual void start_attach_request(srslte::proc_state_t* proc_result) = 0;
virtual bool detach_request(const bool switch_off) = 0;
};
// PDCP interface for RRC
class pdcp_interface_rrc
{
public:
virtual void reestablish() = 0;
virtual void reestablish(uint32_t lcid) = 0;
virtual void reset() = 0;
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking = true) = 0;
virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0;
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
virtual void config_security(uint32_t lcid,
uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
uint8_t *k_up_enc_,
virtual void reestablish() = 0;
virtual void reestablish(uint32_t lcid) = 0;
virtual void reset() = 0;
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking = true) = 0;
virtual void add_bearer(uint32_t lcid, srslte::pdcp_config_t cnfg) = 0;
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
virtual void config_security(uint32_t lcid,
uint8_t* k_rrc_enc_,
uint8_t* k_rrc_int_,
uint8_t* k_up_enc_,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void config_security_all(uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
uint8_t *k_up_enc_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void config_security_all(uint8_t* k_rrc_enc_,
uint8_t* k_rrc_int_,
uint8_t* k_up_enc_,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void enable_integrity(uint32_t lcid) = 0;
virtual void enable_encryption(uint32_t lcid) = 0;
virtual uint32_t get_dl_count(uint32_t lcid) = 0;
virtual uint32_t get_ul_count(uint32_t lcid) = 0;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void enable_integrity(uint32_t lcid) = 0;
virtual void enable_encryption(uint32_t lcid) = 0;
};
// PDCP interface for RLC
@ -325,30 +315,6 @@ public:
virtual void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0;
};
//BSR interface for MUX
class bsr_interface_mux
{
public:
typedef enum {
LONG_BSR,
SHORT_BSR,
TRUNC_BSR
} bsr_format_t;
typedef struct {
bsr_format_t format;
uint32_t buff_size[4];
} bsr_t;
/* MUX calls BSR to check if it can fit a BSR into PDU */
virtual bool need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr) = 0;
/* MUX calls BSR to let it generate a padding BSR if there is space in PDU */
virtual bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr) = 0;
};
/** MAC interface
*
*/
@ -372,6 +338,7 @@ public:
uint32_t pid;
uint16_t rnti;
bool is_sps_release;
uint32_t tti;
} mac_grant_dl_t;
typedef struct {
@ -380,6 +347,7 @@ public:
uint16_t rnti;
bool phich_available;
bool hi_value;
uint32_t tti_tx;
} mac_grant_ul_t;
typedef struct {
@ -449,196 +417,12 @@ public:
uint64_t contention_id;
} ue_rnti_t;
typedef struct ul_harq_cfg_t {
uint32_t max_harq_msg3_tx;
uint32_t max_harq_tx;
ul_harq_cfg_t() { reset(); }
void reset()
{
max_harq_msg3_tx = 5;
max_harq_tx = 5;
}
} ul_harq_cfg_t;
};
/* Interface RRC -> MAC */
class mac_interface_rrc : public mac_interface_rrc_common
{
public:
typedef struct bsr_cfg_t {
int periodic_timer;
int retx_timer;
bsr_cfg_t() { reset(); }
void reset()
{
periodic_timer = -1;
retx_timer = 2560;
}
} bsr_cfg_t;
typedef struct phr_cfg_t {
bool enabled;
int periodic_timer;
int prohibit_timer;
int db_pathloss_change;
bool extended;
phr_cfg_t() { reset(); }
void reset()
{
enabled = false;
periodic_timer = -1;
prohibit_timer = -1;
db_pathloss_change = -1;
extended = false;
}
} phr_cfg_t;
typedef struct sr_cfg_t {
bool enabled;
int dsr_transmax;
sr_cfg_t() { reset(); }
void reset()
{
enabled = false;
dsr_transmax = 0;
}
} sr_cfg_t;
typedef struct rach_cfg_t {
bool enabled;
uint32_t nof_preambles;
uint32_t nof_groupA_preambles;
int32_t messagePowerOffsetGroupB;
uint32_t messageSizeGroupA;
uint32_t responseWindowSize;
uint32_t powerRampingStep;
uint32_t preambleTransMax;
int32_t iniReceivedTargetPower;
uint32_t contentionResolutionTimer;
uint32_t new_ra_msg_len;
rach_cfg_t() { reset(); }
void reset()
{
enabled = false;
nof_preambles = 0;
nof_groupA_preambles = 0;
messagePowerOffsetGroupB = 0;
messageSizeGroupA = 0;
responseWindowSize = 0;
powerRampingStep = 0;
preambleTransMax = 0;
iniReceivedTargetPower = 0;
contentionResolutionTimer = 0;
new_ra_msg_len = 0;
}
} rach_cfg_t;
class mac_cfg_t
{
public:
// Default constructor with default values as in 36.331 9.2.2
mac_cfg_t() { set_defaults(); }
void set_defaults()
{
rach_cfg.reset();
set_mac_main_cfg_default();
}
void set_mac_main_cfg_default()
{
bsr_cfg.reset();
phr_cfg.reset();
sr_cfg.reset();
harq_cfg.reset();
time_alignment_timer = -1;
}
// Called only if section is present
void set_sched_request_cfg(asn1::rrc::sched_request_cfg_c& cfg)
{
sr_cfg.enabled = cfg.type() == asn1::rrc::setup_e::setup;
if (sr_cfg.enabled) {
sr_cfg.dsr_transmax = cfg.setup().dsr_trans_max.to_number();
}
}
// MAC-MainConfig section is always present
void set_mac_main_cfg(asn1::rrc::mac_main_cfg_s& cfg)
{
// Update values only if each section is present
if (cfg.phr_cfg_present) {
phr_cfg.enabled = cfg.phr_cfg.type() == asn1::rrc::setup_e::setup;
if (phr_cfg.enabled) {
phr_cfg.prohibit_timer = cfg.phr_cfg.setup().prohibit_phr_timer.to_number();
phr_cfg.periodic_timer = cfg.phr_cfg.setup().periodic_phr_timer.to_number();
phr_cfg.db_pathloss_change = cfg.phr_cfg.setup().dl_pathloss_change.to_number();
}
}
if (cfg.mac_main_cfg_v1020_present) {
typedef asn1::rrc::mac_main_cfg_s::mac_main_cfg_v1020_s_ mac_main_cfg_v1020_t;
mac_main_cfg_v1020_t* mac_main_cfg_v1020 = cfg.mac_main_cfg_v1020.get();
phr_cfg.extended = mac_main_cfg_v1020->extended_phr_r10_present;
}
if (cfg.ul_sch_cfg_present) {
bsr_cfg.periodic_timer = cfg.ul_sch_cfg.periodic_bsr_timer.to_number();
bsr_cfg.retx_timer = cfg.ul_sch_cfg.retx_bsr_timer.to_number();
if (cfg.ul_sch_cfg.max_harq_tx_present) {
harq_cfg.max_harq_tx = cfg.ul_sch_cfg.max_harq_tx.to_number();
}
}
// TimeAlignmentDedicated overwrites Common??
time_alignment_timer = cfg.time_align_timer_ded.to_number();
}
// RACH-Common section is always present
void set_rach_cfg_common(asn1::rrc::rach_cfg_common_s& cfg)
{
// Preamble info
rach_cfg.nof_preambles = cfg.preamb_info.nof_ra_preambs.to_number();
if (cfg.preamb_info.preambs_group_a_cfg_present) {
rach_cfg.nof_groupA_preambles = cfg.preamb_info.preambs_group_a_cfg.size_of_ra_preambs_group_a.to_number();
rach_cfg.messageSizeGroupA = cfg.preamb_info.preambs_group_a_cfg.msg_size_group_a.to_number();
rach_cfg.messagePowerOffsetGroupB = cfg.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number();
} else {
rach_cfg.nof_groupA_preambles = 0;
}
// Power ramping
rach_cfg.powerRampingStep = cfg.pwr_ramp_params.pwr_ramp_step.to_number();
rach_cfg.iniReceivedTargetPower = cfg.pwr_ramp_params.preamb_init_rx_target_pwr.to_number();
// Supervision info
rach_cfg.preambleTransMax = cfg.ra_supervision_info.preamb_trans_max.to_number();
rach_cfg.responseWindowSize = cfg.ra_supervision_info.ra_resp_win_size.to_number();
rach_cfg.contentionResolutionTimer = cfg.ra_supervision_info.mac_contention_resolution_timer.to_number();
// HARQ Msg3
harq_cfg.max_harq_msg3_tx = cfg.max_harq_msg3_tx;
}
void set_time_alignment(asn1::rrc::time_align_timer_e time_alignment_timer)
{
this->time_alignment_timer = time_alignment_timer.to_number();
}
bsr_cfg_t& get_bsr_cfg() { return bsr_cfg; }
phr_cfg_t& get_phr_cfg() { return phr_cfg; }
rach_cfg_t& get_rach_cfg() { return rach_cfg; }
sr_cfg_t& get_sr_cfg() { return sr_cfg; }
ul_harq_cfg_t& get_harq_cfg() { return harq_cfg; }
int get_time_alignment_timer() { return time_alignment_timer; }
private:
bsr_cfg_t bsr_cfg;
phr_cfg_t phr_cfg;
sr_cfg_t sr_cfg;
rach_cfg_t rach_cfg;
ul_harq_cfg_t harq_cfg;
int time_alignment_timer;
};
virtual void clear_rntis() = 0;
/* Instructs the MAC to start receiving BCCH */
@ -656,7 +440,7 @@ public:
virtual uint32_t get_current_tti() = 0;
virtual void set_config(mac_cfg_t& mac_cfg) = 0;
virtual void set_config(srslte::mac_cfg_t& mac_cfg) = 0;
virtual void get_rntis(ue_rnti_t *rntis) = 0;
virtual void set_contention_id(uint64_t uecri) = 0;
@ -791,45 +575,21 @@ public:
class phy_interface_rrc_lte
{
public:
struct phy_cfg_common_t {
asn1::rrc::prach_cfg_sib_s prach_cnfg;
asn1::rrc::pdsch_cfg_common_s pdsch_cnfg;
asn1::rrc::pusch_cfg_common_s pusch_cnfg;
asn1::rrc::phich_cfg_s phich_cnfg;
asn1::rrc::pucch_cfg_common_s pucch_cnfg;
asn1::rrc::srs_ul_cfg_common_c srs_ul_cnfg;
asn1::rrc::ul_pwr_ctrl_common_s ul_pwr_ctrl;
asn1::rrc::tdd_cfg_s tdd_cnfg;
asn1::rrc::srs_ant_port_e ant_info;
bool rrc_enable_64qam;
};
struct phy_cfg_mbsfn_t {
asn1::rrc::mbsfn_sf_cfg_s mbsfn_subfr_cnfg;
asn1::rrc::mbms_notif_cfg_r9_s mbsfn_notification_cnfg;
asn1::rrc::mbsfn_area_info_r9_s mbsfn_area_info;
asn1::rrc::mcch_msg_s mcch;
};
typedef struct {
asn1::rrc::phys_cfg_ded_s dedicated;
phy_cfg_common_t common;
phy_cfg_mbsfn_t mbsfn;
} phy_cfg_t;
virtual void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL) = 0;
virtual uint32_t get_current_earfcn() = 0;
virtual uint32_t get_current_pci() = 0;
virtual void set_config(phy_cfg_t* config) = 0;
virtual void set_config_scell(asn1::rrc::scell_to_add_mod_r10_s* scell_config) = 0;
virtual void set_config_tdd(asn1::rrc::tdd_cfg_s* tdd) = 0;
virtual void set_config_mbsfn_sib2(asn1::rrc::sib_type2_s* sib2) = 0;
virtual void set_config_mbsfn_sib13(asn1::rrc::sib_type13_r9_s* sib13) = 0;
virtual void set_config_mbsfn_mcch(asn1::rrc::mcch_msg_s* mcch) = 0;
virtual void get_current_cell(srslte_cell_t* cell, uint32_t* current_earfcn = NULL) = 0;
virtual uint32_t get_current_earfcn() = 0;
virtual uint32_t get_current_pci() = 0;
virtual void set_config(srslte::phy_cfg_t& config,
uint32_t cc_idx = 0,
uint32_t earfcn = 0,
srslte_cell_t* cell_info = nullptr) = 0;
virtual void set_config_tdd(srslte_tdd_config_t& tdd_config) = 0;
virtual void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) = 0;
virtual void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) = 0;
virtual void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) = 0;
/* Measurements interface */
virtual void meas_reset() = 0;
virtual void meas_reset() = 0;
virtual int meas_start(uint32_t earfcn, int pci = -1) = 0;
virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0;
@ -864,6 +624,21 @@ class gw_interface_stack : public gw_interface_nas, public gw_interface_rrc, pub
{
};
// STACK interface for MAC
class stack_interface_mac
{
public:
virtual void process_pdus() = 0;
virtual void wait_ra_completion(uint16_t rnti) = 0;
};
// STACK interface for RRC
class stack_interface_rrc
{
public:
virtual void start_cell_search() = 0;
};
// Combined interface for PHY to access stack (MAC and RRC)
class stack_interface_phy_lte : public mac_interface_phy_lte, public rrc_interface_phy_lte
{

@ -64,6 +64,8 @@ typedef struct SRSLTE_API {
uint32_t I_srs;
uint32_t k_tc;
uint32_t n_rrc;
bool dedicated_enabled;
bool common_enabled;
bool configured;
} srslte_refsignal_srs_cfg_t;

@ -24,10 +24,10 @@
#include "delay.h"
#include "fading.h"
#include "hst.h"
#include "rlf.h"
#include <memory>
#include <srslte/config.h>
#include <srslte/srslte.h>
#include <srslte/common/log_filter.h>
#include <string>
namespace srslte {
@ -43,11 +43,18 @@ public:
bool fading_enable = false;
std::string fading_model = "none";
// High Speed Train options
bool hst_enable = false;
float hst_fd_hz = 750.0f;
float hst_period_s = 7.2f;
float hst_init_time_s = 0.0f;
// Delay options
bool delay_enable = false;
float delay_min_us = 10;
float delay_max_us = 100;
uint32_t delay_period_s = 3600;
bool delay_enable = false;
float delay_min_us = 10;
float delay_max_us = 100;
float delay_period_s = 3600;
float delay_init_time_s = 0;
// RLF options
bool rlf_enable = false;
@ -57,15 +64,18 @@ public:
channel(const args_t& channel_args, uint32_t _nof_ports);
~channel();
void set_logger(log_filter* _log_h);
void set_srate(uint32_t srate);
void run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint32_t len, const srslte_timestamp_t& t);
private:
srslte_channel_fading_t* fading[SRSLTE_MAX_PORTS] = {};
srslte_channel_delay_t* delay[SRSLTE_MAX_PORTS] = {};
srslte_channel_hst_t* hst = nullptr; // HST has no buffers / no multiple instance is required
srslte_channel_rlf_t* rlf = nullptr; // RLF has no buffers / no multiple instance is required
cf_t* buffer_in = nullptr;
cf_t* buffer_out = nullptr;
log_filter* log_h = nullptr;
uint32_t nof_ports = 0;
uint32_t current_srate = 0;
args_t args = {};

@ -22,16 +22,17 @@
#ifndef SRSLTE_DELAY_H
#define SRSLTE_DELAY_H
#include <srslte/config.h>
#include <srslte/phy/common/timestamp.h>
#include <srslte/phy/utils/ringbuffer.h>
#include <srslte/srslte.h>
typedef struct {
float delay_min_us;
float delay_max_us;
uint32_t period_s;
float period_s;
float init_time_s;
uint32_t srate_max_hz;
uint32_t srate_hz;
float delay_us;
float delay_nsamples;
srslte_ringbuffer_t rb;
cf_t* zero_buffer;
@ -41,8 +42,12 @@ typedef struct {
extern "C" {
#endif
SRSLTE_API int srslte_channel_delay_init(
srslte_channel_delay_t* q, float delay_min_ns, float delay_max_ns, uint32_t period_s, uint32_t srate_max_hz);
SRSLTE_API int srslte_channel_delay_init(srslte_channel_delay_t* q,
float delay_min_us,
float delay_max_us,
float period_s,
float init_time_s,
uint32_t srate_max_hz);
SRSLTE_API void srslte_channel_delay_update_srate(srslte_channel_delay_t* q, uint32_t srate_hz);

@ -22,8 +22,8 @@
#ifndef SRSLTE_FADING_H
#define SRSLTE_FADING_H
#include "srslte/phy/dft/dft.h"
#include <inttypes.h>
#include <srslte/srslte.h>
#define SRSLTE_CHANNEL_FADING_MAXTAPS 9

@ -0,0 +1,59 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_HST_H_
#define SRSLTE_HST_H_
#include <srslte/srslte.h>
typedef struct {
// System parameters
uint32_t srate_hz; // Sampling rate
// Model Parameters
float fd_hz; // Maximum Doppler Frequency
float ds_m; // eNb distance [m]
float dmin_m; // eNb Rail-track distance [m]
float period_s; // 2 * Ds / speed [s]
float init_time_s; // Time offset [s]
// State
float fs_hz; // Last doppler dispersion [Hz]
} srslte_channel_hst_t;
#ifdef __cplusplus
extern "C" {
#endif
SRSLTE_API int srslte_channel_hst_init(srslte_channel_hst_t* q, float fd_hz, float period_d, float init_time_s);
SRSLTE_API void srslte_channel_hst_update_srate(srslte_channel_hst_t* q, uint32_t srate);
SRSLTE_API void
srslte_channel_hst_execute(srslte_channel_hst_t* q, cf_t* in, cf_t* out, uint32_t len, const srslte_timestamp_t* ts);
SRSLTE_API void srslte_channel_hst_free(srslte_channel_hst_t* q);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_HST_H_

@ -22,8 +22,7 @@
#ifndef SRSLTE_RLF_H
#define SRSLTE_RLF_H
#include <srslte/config.h>
#include <srslte/phy/common/timestamp.h>
#include <srslte/srslte.h>
typedef struct {
uint32_t t_on_ms;

@ -258,6 +258,9 @@ typedef enum {
SRSLTE_DCI_FORMAT2B,
// SRSLTE_DCI_FORMAT3,
// SRSLTE_DCI_FORMAT3A,
SRSLTE_DCI_FORMATN0,
SRSLTE_DCI_FORMATN1,
SRSLTE_DCI_FORMATN2,
SRSLTE_DCI_NOF_FORMATS
} srslte_dci_format_t;
@ -283,6 +286,43 @@ enum band_geographical_area {
SRSLTE_BAND_GEO_AREA_NA
};
// NB-IoT specific structs
typedef enum {
SRSLTE_NBIOT_MODE_INBAND_SAME_PCI = 0,
SRSLTE_NBIOT_MODE_INBAND_DIFFERENT_PCI,
SRSLTE_NBIOT_MODE_GUARDBAND,
SRSLTE_NBIOT_MODE_STANDALONE,
SRSLTE_NBIOT_MODE_N_ITEMS,
} srslte_nbiot_mode_t;
typedef struct SRSLTE_API {
srslte_cell_t base; // the umbrella or super cell
uint32_t nbiot_prb; // the index of the NB-IoT PRB within the cell
uint32_t n_id_ncell;
uint32_t nof_ports; // The number of antenna ports for NB-IoT
bool is_r14; // Whether the cell is a R14 cell
srslte_nbiot_mode_t mode;
} srslte_nbiot_cell_t;
#define SRSLTE_NBIOT_MAX_PORTS 2
#define SRSLTE_NBIOT_MAX_CODEWORDS SRSLTE_MAX_CODEWORDS
#define SRSLTE_SF_LEN_PRB_NBIOT (SRSLTE_SF_LEN_PRB(1))
#define SRSLTE_SF_LEN_RE_NBIOT (SRSLTE_SF_LEN_RE(1, SRSLTE_CP_NORM))
#define SRSLTE_NBIOT_FFT_SIZE 128
#define SRSLTE_NBIOT_FREQ_SHIFT_FACTOR ((float)-0.5)
#define SRSLTE_NBIOT_NUM_RX_ANTENNAS 1
#define SRSLTE_NBIOT_MAX_PRB 1
#define SRSLTE_NBIOT_DEFAULT_NUM_PRB_BASECELL 1
#define SRSLTE_NBIOT_DEFAULT_PRB_OFFSET 0
#define SRSLTE_DEFAULT_MAX_FRAMES_NPBCH 500
#define SRSLTE_DEFAULT_MAX_FRAMES_NPSS 20
#define SRSLTE_DEFAULT_NOF_VALID_NPSS_FRAMES 20
SRSLTE_API bool srslte_cell_isvalid(srslte_cell_t *cell);
SRSLTE_API void srslte_cell_fprint(FILE *stream,
@ -386,4 +426,10 @@ SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2);
SRSLTE_API uint32_t srslte_print_check(char* s, size_t max_len, uint32_t cur_len, const char* format, ...);
SRSLTE_API bool srslte_nbiot_cell_isvalid(srslte_nbiot_cell_t* cell);
SRSLTE_API bool srslte_nbiot_portid_isvalid(uint32_t port_id);
SRSLTE_API float srslte_band_fu_nbiot(uint32_t ul_earfcn, const float m_ul);
SRSLTE_API char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode);
#endif // SRSLTE_PHY_COMMON_H

@ -33,6 +33,7 @@
#define SRSLTE_FILESINK_H
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "srslte/config.h"

@ -67,6 +67,8 @@ SRSLTE_API int srslte_netsource_read(srslte_netsource_t *q,
void *buffer,
int nof_bytes);
SRSLTE_API int srslte_netsource_write(srslte_netsource_t* q, void* buffer, int nbytes);
SRSLTE_API int srslte_netsource_set_timeout(srslte_netsource_t *q,
uint32_t microseconds);

@ -52,6 +52,7 @@
typedef struct {
bool multiple_csi_request_enabled;
bool cif_enabled;
bool cif_present;
bool srs_request_enabled;
bool ra_format_enabled;
} srslte_dci_cfg_t;
@ -160,8 +161,9 @@ typedef struct SRSLTE_API {
// Release 10
uint32_t cif;
bool cif_present;
uint8_t multiple_csi_request;
bool multiple_csi_request_present;
uint32_t srs_request;
bool srs_request;
bool srs_request_present;
srslte_ra_type_t ra_type;
bool ra_type_present;

@ -60,6 +60,7 @@ typedef struct SRSLTE_API {
float rs_power;
bool power_scale;
bool csi_enable;
bool use_tbs_index_alt;
union {
srslte_softbuffer_tx_t* tx[SRSLTE_MAX_CODEWORDS];

@ -62,9 +62,8 @@ typedef struct SRSLTE_API {
uint32_t n_pucch_2;
uint32_t n_pucch_sr;
bool simul_cqi_ack;
bool tdd_ack_bundle; // if false, multiplex
bool tdd_ack_multiplex; // if false, bundle
bool sps_enabled;
uint32_t tpc_for_pucch;
// Release 10 CA specific
srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode;

@ -127,6 +127,10 @@ SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg,
uint32_t nof_bits,
bool is_ri);
SRSLTE_API uint32_t srslte_uci_cfg_total_ack(srslte_uci_cfg_t* uci_cfg);
SRSLTE_API void srslte_uci_data_reset(srslte_uci_data_t* uci_data);
SRSLTE_API int srslte_uci_data_info(srslte_uci_cfg_t* uci_cfg,
srslte_uci_value_t* uci_data,
char* str,

@ -39,12 +39,13 @@ typedef struct SRSLTE_API {
uint32_t N_bundle;
uint32_t tdd_ack_M;
uint32_t tdd_ack_m;
bool tdd_is_bundling;
bool has_scell_ack;
bool tdd_is_multiplex;
uint32_t tpc_for_pucch;
uint32_t grant_cc_idx;
} srslte_uci_cfg_ack_t;
typedef struct SRSLTE_API {
srslte_uci_cfg_ack_t ack;
srslte_uci_cfg_ack_t ack[SRSLTE_MAX_CARRIERS];
srslte_cqi_cfg_t cqi;
bool is_scheduling_request_tti;
} srslte_uci_cfg_t;

@ -92,17 +92,9 @@ SRSLTE_API void srslte_rf_flush_buffer(srslte_rf_t *h);
SRSLTE_API bool srslte_rf_has_rssi(srslte_rf_t *h);
SRSLTE_API float srslte_rf_get_rssi(srslte_rf_t *h);
SRSLTE_API float srslte_rf_get_rssi(srslte_rf_t* h);
SRSLTE_API bool srslte_rf_rx_wait_lo_locked(srslte_rf_t *h);
SRSLTE_API void srslte_rf_set_master_clock_rate(srslte_rf_t *h,
double rate);
SRSLTE_API bool srslte_rf_is_master_clock_dynamic(srslte_rf_t *h);
SRSLTE_API double srslte_rf_set_rx_srate(srslte_rf_t *h,
double freq);
SRSLTE_API double srslte_rf_set_rx_srate(srslte_rf_t* h, double freq);
SRSLTE_API double srslte_rf_set_rx_gain(srslte_rf_t *h,
double gain);

@ -0,0 +1,123 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: npss.h
*
* Description: Narrowband Primary synchronization signal (NPSS) generation and detection.
*
* The srslte_npss_synch_t object provides functions for fast
* computation of the crosscorrelation between the NPSS and received
* signal and CFO estimation. Also, the function srslte_npss_synch_tperiodic()
* is designed to be called periodically every subframe, taking
* care of the correct data alignment with respect to the NPSS sequence.
*
* The object is designed to work with signals sampled at ?.? Mhz
* centered at the carrier frequency. Thus, downsampling is required
* if the signal is sampled at higher frequencies.
*
* Reference: 3GPP TS 36.211 version 13.2.0 Release 13 Sec. 10.x.x
*****************************************************************************/
#ifndef SRSLTE_NPSS_H
#define SRSLTE_NPSS_H
#include <stdbool.h>
#include <stdint.h>
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/utils/convolution.h"
#define CONVOLUTION_FFT
#define SRSLTE_NPSS_RETURN_PSR
#define SRSLTE_NPSS_LEN 11
#define SRSLTE_NPSS_NUM_OFDM_SYMS 11
#define SRSLTE_NPSS_TOT_LEN (SRSLTE_NPSS_LEN * SRSLTE_NPSS_NUM_OFDM_SYMS)
#define SRSLTE_NPSS_CORR_FILTER_LEN \
((SRSLTE_NPSS_NUM_OFDM_SYMS * SRSLTE_NBIOT_FFT_SIZE) + \
(SRSLTE_NPSS_NUM_OFDM_SYMS - 1) * SRSLTE_CP_LEN_NORM(1, SRSLTE_NBIOT_FFT_SIZE) + \
SRSLTE_CP_LEN_NORM(0, SRSLTE_NBIOT_FFT_SIZE))
// The below value corresponds to the time-domain representation of the first
// three OFDM-symbols plus cyclic prefix that are not transmitted in the sub-frame
// carrying the NPSS
#define SRSLTE_NPSS_CORR_OFFSET (SRSLTE_SF_LEN(SRSLTE_NBIOT_FFT_SIZE) - SRSLTE_NPSS_CORR_FILTER_LEN)
// CFO estimation based on the NPSS is done using the second slot of the sub-frame
#define SRSLTE_NPSS_CFO_OFFSET (SRSLTE_SF_LEN(SRSLTE_NBIOT_FFT_SIZE) / 2 - SRSLTE_NPSS_CORR_OFFSET)
#define SRSLTE_NPSS_CFO_NUM_SYMS 6 // number of symbols for CFO estimation
#define SRSLTE_NPSS_CFO_NUM_SAMPS \
((SRSLTE_NPSS_CFO_NUM_SYMS * SRSLTE_NBIOT_FFT_SIZE) + \
(SRSLTE_NPSS_CFO_NUM_SYMS - 1) * SRSLTE_CP_LEN_NORM(1, SRSLTE_NBIOT_FFT_SIZE) + \
SRSLTE_CP_LEN_NORM(0, SRSLTE_NBIOT_FFT_SIZE)) // resulting number of samples
// NPSS processing options
#define SRSLTE_NPSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to
// srslte_pss_synch_find_pss
#define SRSLTE_NPSS_ABS_SQUARE // If enabled, compute abs square, otherwise computes absolute value only
#define SRSLTE_NPSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value
/* Low-level API */
typedef struct SRSLTE_API {
#ifdef CONVOLUTION_FFT
srslte_conv_fft_cc_t conv_fft;
#endif
uint32_t frame_size, max_frame_size;
uint32_t fft_size, max_fft_size;
cf_t* npss_signal_time;
cf_t* tmp_input;
cf_t* conv_output;
float* conv_output_abs;
float ema_alpha;
float* conv_output_avg;
float peak_value;
} srslte_npss_synch_t;
// Basic functionality
SRSLTE_API int srslte_npss_synch_init(srslte_npss_synch_t* q, uint32_t frame_size, uint32_t fft_size);
SRSLTE_API void srslte_npss_synch_reset(srslte_npss_synch_t* q);
SRSLTE_API int srslte_npss_synch_resize(srslte_npss_synch_t* q, uint32_t frame_size, uint32_t fft_size);
SRSLTE_API void srslte_npss_synch_set_ema_alpha(srslte_npss_synch_t* q, float alpha);
SRSLTE_API void srslte_npss_synch_free(srslte_npss_synch_t* q);
SRSLTE_API int srslte_npss_sync_find(srslte_npss_synch_t* q, cf_t* input, float* corr_peak_value);
// Internal functions
SRSLTE_API int srslte_npss_corr_init(cf_t* npss_signal_time, uint32_t fft_size, uint32_t frame_size);
SRSLTE_API int srslte_npss_generate(cf_t* signal);
SRSLTE_API void srslte_npss_put_subframe(
srslte_npss_synch_t* q, cf_t* npss_signal, cf_t* sf, const uint32_t nof_prb, const uint32_t nbiot_prb_offset);
#endif // SRSLTE_NPSS_H

@ -0,0 +1,116 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: nsss.h
*
* Description: Narrowband secondary synchronization signal (NSSS)
* generation and detection.
*
*
* Reference: 3GPP TS 36.211 version 13.2.0 Release 13 Sec. 10.2.7.2
*****************************************************************************/
#ifndef SRSLTE_NSSS_H
#define SRSLTE_NSSS_H
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/dft/dft.h"
#include "srslte/phy/utils/convolution.h"
#define SRSLTE_NSSS_NSYMB 11
#define SRSLTE_NSSS_NSC 12
#define SRSLTE_NSSS_LEN (SRSLTE_NSSS_NSYMB * SRSLTE_NSSS_NSC)
#define SRSLTE_NSSS_NUM_SEQ 4
#define SRSLTE_NSSS_TOT_LEN (SRSLTE_NSSS_NUM_SEQ * SRSLTE_NSSS_LEN)
#define SRSLTE_NSSS_CORR_FILTER_LEN 1508
#define SRSLTE_NSSS_CORR_OFFSET 412
#define SRSLTE_NUM_PCI 504
#define SRSLTE_NSSS_PERIOD 2
#define SRSLTE_NSSS_NUM_SF_DETECT (SRSLTE_NSSS_PERIOD)
// b_q_m table from 3GPP TS 36.211 v13.2.0 table 10.2.7.2.1-1
static const int b_q_m[SRSLTE_NSSS_NUM_SEQ][128] = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1,
1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1,
1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1,
1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1},
{1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1,
-1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1,
-1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1,
-1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1,
1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1},
{1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1,
-1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1,
-1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1,
1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1,
-1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1}};
/* Low-level API */
typedef struct SRSLTE_API {
uint32_t input_size;
uint32_t subframe_sz;
uint32_t fft_size, max_fft_size;
srslte_conv_fft_cc_t conv_fft;
cf_t* nsss_signal_time[SRSLTE_NUM_PCI];
cf_t* tmp_input;
cf_t* conv_output;
float* conv_output_abs;
float peak_values[SRSLTE_NUM_PCI];
float corr_peak_threshold;
} srslte_nsss_synch_t;
SRSLTE_API int srslte_nsss_synch_init(srslte_nsss_synch_t* q, uint32_t input_size, uint32_t fft_size);
SRSLTE_API void srslte_nsss_synch_free(srslte_nsss_synch_t* q);
SRSLTE_API int srslte_nsss_synch_resize(srslte_nsss_synch_t* q, uint32_t fft_size);
SRSLTE_API int srslte_nsss_sync_find(
srslte_nsss_synch_t* q, cf_t* input, float* corr_peak_value, uint32_t* cell_id, uint32_t* sfn_partial);
void srslte_nsss_sync_find_pci(srslte_nsss_synch_t* q, cf_t* input, uint32_t cell_id);
SRSLTE_API int srslte_nsss_corr_init(srslte_nsss_synch_t* q);
SRSLTE_API void srslte_nsss_generate(cf_t* signal, uint32_t cell_id);
SRSLTE_API void srslte_nsss_put_subframe(srslte_nsss_synch_t* q,
cf_t* nsss,
cf_t* subframe,
const int nf,
const uint32_t nof_prb,
const uint32_t nbiot_prb_offset);
#endif // SRSLTE_NSSS_H

@ -0,0 +1,58 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_REFSIGNAL_DL_SYNC_H_
#define SRSLTE_REFSIGNAL_DL_SYNC_H_
#include <srslte/phy/ch_estimation/refsignal_dl.h>
#include <srslte/phy/dft/ofdm.h>
#include <srslte/phy/utils/convolution.h>
typedef struct {
srslte_refsignal_t refsignal;
srslte_ofdm_t ifft;
cf_t* ifft_buffer_in;
cf_t* ifft_buffer_out;
cf_t* sequences[SRSLTE_NOF_SF_X_FRAME];
cf_t* correlation;
srslte_conv_fft_cc_t conv_fft_cc;
// Results
bool found;
float rsrp_dBfs;
float rssi_dBfs;
float rsrq_dB;
float cfo_Hz;
uint32_t peak_index;
} srslte_refsignal_dl_sync_t;
SRSLTE_API int srslte_refsignal_dl_sync_init(srslte_refsignal_dl_sync_t* q);
SRSLTE_API int srslte_refsignal_dl_sync_set_cell(srslte_refsignal_dl_sync_t* q, srslte_cell_t cell);
SRSLTE_API void srslte_refsignal_dl_sync_free(srslte_refsignal_dl_sync_t* q);
SRSLTE_API void srslte_refsignal_dl_sync_run(srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples);
SRSLTE_API void srslte_refsignal_dl_sync_measure_sf(
srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t sf_idx, float* rsrp, float* rssi, float* cfo);
#endif // SRSLTE_REFSIGNAL_DL_SYNC_H_

@ -131,9 +131,7 @@ SRSLTE_API int srslte_sss_m0m1_diff(srslte_sss_t *q,
SRSLTE_API uint32_t srslte_sss_subframe(uint32_t m0,
uint32_t m1);
SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t *q,
uint32_t m0,
uint32_t m1);
SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t* q, uint32_t m0, uint32_t m1, float corr);
SRSLTE_API int srslte_sss_frame(srslte_sss_t *q,
cf_t *input,

@ -118,6 +118,7 @@ typedef struct SRSLTE_API {
bool sss_generated;
bool sss_detected;
bool sss_available;
float sss_corr;
srslte_dft_plan_t idftp_sss;
cf_t sss_recv[SRSLTE_SYMBOL_SZ_MAX];
cf_t sss_signal[2][SRSLTE_SYMBOL_SZ_MAX];
@ -242,6 +243,8 @@ SRSLTE_API srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q);
SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q);
SRSLTE_API float srslte_sync_sss_correlation_peak(srslte_sync_t* q);
SRSLTE_API bool srslte_sync_sss_available(srslte_sync_t* q);
/* Enables/Disables CP detection */

@ -0,0 +1,125 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: sync_nbiot.h
*
* Description: Time and frequency synchronization using the NPSS and NSSS signals.
*
* The object is designed to work with signals sampled at 1.92 Mhz
* centered at the carrier frequency. Thus, downsampling is required
* if the signal is sampled at higher frequencies.
*
* Correlation peak is detected comparing the maximum at the output
* of the correlator with a threshold.
*
* Reference: 3GPP TS 36.211 version 13.2.0 Release 13
*****************************************************************************/
#ifndef SRSLTE_SYNC_NBIOT_H
#define SRSLTE_SYNC_NBIOT_H
#include <math.h>
#include <stdbool.h>
#include "srslte/config.h"
#include "srslte/phy/sync/npss.h"
#include "srslte/phy/sync/nsss.h"
#include "srslte/phy/sync/sync.h"
#include "srslte/phy/ue/ue_sync.h"
#define MAX_NUM_CFO_CANDITATES 50
typedef struct SRSLTE_API {
srslte_npss_synch_t npss;
srslte_nsss_synch_t nsss;
srslte_cp_synch_t cp_synch;
uint32_t n_id_ncell;
float threshold;
float peak_value;
uint32_t fft_size;
uint32_t frame_size;
uint32_t max_frame_size;
uint32_t max_offset;
bool enable_cfo_estimation;
bool enable_cfo_cand_test;
float cfo_cand[MAX_NUM_CFO_CANDITATES];
int cfo_num_cand;
int cfo_cand_idx;
float mean_cfo;
float current_cfo_tol;
cf_t* shift_buffer;
cf_t* cfo_output;
int cfo_i;
bool find_cfo_i;
bool find_cfo_i_initiated;
float cfo_ema_alpha;
uint32_t nof_symbols;
uint32_t cp_len;
srslte_cfo_t cfocorr;
srslte_cp_t cp;
} srslte_sync_nbiot_t;
SRSLTE_API int
srslte_sync_nbiot_init(srslte_sync_nbiot_t* q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size);
SRSLTE_API void srslte_sync_nbiot_free(srslte_sync_nbiot_t* q);
SRSLTE_API int
srslte_sync_nbiot_resize(srslte_sync_nbiot_t* q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size);
SRSLTE_API srslte_sync_find_ret_t srslte_sync_nbiot_find(srslte_sync_nbiot_t* q,
cf_t* input,
uint32_t find_offset,
uint32_t* peak_position);
SRSLTE_API float cfo_estimate_nbiot(srslte_sync_nbiot_t* q, cf_t* input);
SRSLTE_API void srslte_sync_nbiot_set_threshold(srslte_sync_nbiot_t* q, float threshold);
SRSLTE_API void srslte_sync_nbiot_set_cfo_enable(srslte_sync_nbiot_t* q, bool enable);
SRSLTE_API void srslte_sync_nbiot_set_cfo_cand_test_enable(srslte_sync_nbiot_t* q, bool enable);
SRSLTE_API int srslte_sync_nbiot_set_cfo_cand(srslte_sync_nbiot_t* q, const float* cand, const int num);
SRSLTE_API void srslte_sync_nbiot_set_cfo_tol(srslte_sync_nbiot_t* q, float tol);
SRSLTE_API void srslte_sync_nbiot_set_cfo_ema_alpha(srslte_sync_nbiot_t* q, float alpha);
SRSLTE_API void srslte_sync_nbiot_set_npss_ema_alpha(srslte_sync_nbiot_t* q, float alpha);
SRSLTE_API int srslte_sync_nbiot_find_cell_id(srslte_sync_nbiot_t* q, cf_t* input);
SRSLTE_API int srslte_sync_nbiot_get_cell_id(srslte_sync_nbiot_t* q);
SRSLTE_API float srslte_sync_nbiot_get_cfo(srslte_sync_nbiot_t* q);
SRSLTE_API void srslte_sync_nbiot_set_cfo(srslte_sync_nbiot_t* q, float cfo);
SRSLTE_API bool srslte_sync_nbiot_nsss_detected(srslte_sync_nbiot_t* q);
SRSLTE_API float srslte_sync_nbiot_get_peak_value(srslte_sync_nbiot_t* q);
SRSLTE_API void srslte_sync_nbiot_reset(srslte_sync_nbiot_t* q);
#endif // SRSLTE_SYNC_NBIOT_H

@ -112,21 +112,22 @@ typedef struct SRSLTE_API {
typedef struct SRSLTE_API {
srslte_cqi_report_cfg_t cqi_report;
srslte_pdsch_cfg_t pdsch;
srslte_dci_cfg_t dci;
srslte_tm_t tm;
} srslte_dl_cfg_t;
typedef struct SRSLTE_API {
srslte_dl_cfg_t cfg;
srslte_chest_dl_cfg_t chest_cfg;
srslte_dci_cfg_t dci_cfg;
uint32_t last_ri;
float snr_to_cqi_offset;
bool pdsch_use_tbs_index_alt;
} srslte_ue_dl_cfg_t;
typedef struct {
uint32_t v_dai_dl;
uint32_t n_cce;
uint32_t grant_cc_idx;
uint32_t tpc_for_pucch;
} srslte_pdsch_ack_resource_t;
typedef struct {
@ -149,7 +150,7 @@ typedef struct {
srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode;
bool is_grant_available;
bool is_pusch_available;
bool tdd_ack_bundle;
bool tdd_ack_multiplex;
bool simul_cqi_ack;
} srslte_pdsch_ack_t;
@ -182,13 +183,13 @@ SRSLTE_API int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t* q,
/* Finds UL/DL DCI in the signal processed in a previous call to decode_fft_estimate() */
SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t* q,
srslte_dl_sf_cfg_t* sf,
srslte_ue_dl_cfg_t* cfg,
srslte_ue_dl_cfg_t* dl_cfg,
uint16_t rnti,
srslte_dci_ul_t dci_msg[SRSLTE_MAX_DCI_MSG]);
SRSLTE_API int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t* q,
srslte_dl_sf_cfg_t* sf,
srslte_ue_dl_cfg_t* cfg,
srslte_ue_dl_cfg_t* dl_cfg,
uint16_t rnti,
srslte_dci_dl_t dci_msg[SRSLTE_MAX_DCI_MSG]);

@ -35,7 +35,8 @@ typedef struct {
int wpm;
int rpm;
pthread_mutex_t mutex;
pthread_cond_t cvar;
pthread_cond_t write_cvar;
pthread_cond_t read_cvar;
} srslte_ringbuffer_t;
#ifdef __cplusplus
@ -54,6 +55,8 @@ SRSLTE_API int srslte_ringbuffer_space(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t* q, void* ptr, int nof_bytes);
SRSLTE_API int srslte_ringbuffer_write_timed(srslte_ringbuffer_t* q, void* ptr, int nof_bytes, uint32_t timeout_ms);
SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t* q, void* ptr, int nof_bytes);
SRSLTE_API int srslte_ringbuffer_read_timed(srslte_ringbuffer_t* q, void* p, int nof_bytes, uint32_t timeout_ms);

@ -49,7 +49,6 @@ class radio {
burst_preamble_samples = 0;
burst_preamble_time_rounded = 0;
master_clock_rate = 0;
cur_tx_srate = 0;
tx_adv_sec = 0;
tx_adv_nsamples = 0;
@ -92,6 +91,7 @@ class radio {
bool tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end();
bool get_is_start_of_burst();
bool rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time);
bool rx_at(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
@ -99,7 +99,6 @@ class radio {
void set_rx_gain(float gain);
void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain);
void set_master_clock_rate(double rate);
void set_freq_offset(double freq);
void set_tx_freq(uint32_t chan, double freq);
@ -138,7 +137,6 @@ class radio {
uint32_t burst_preamble_samples;
double burst_preamble_time_rounded; // preamble time rounded to sample time
cf_t* zeros;
double master_clock_rate;
double cur_tx_srate;
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay

@ -57,6 +57,10 @@ public:
bool is_init() override { return radios.at(0)->is_init(); }
void reset() override { return radios.at(0)->reset(); }
bool is_continuous_tx() override { return radios.at(0)->is_continuous_tx(); }
bool get_is_start_of_burst(const uint32_t& radio_idx) override
{
return radios.at(radio_idx)->get_is_start_of_burst();
}
bool tx(const uint32_t& radio_idx,
cf_t* buffer[SRSLTE_MAX_PORTS],
const uint32_t& nof_samples,
@ -64,7 +68,13 @@ public:
{
return radios.at(radio_idx)->tx(buffer, nof_samples, tx_time);
}
void tx_end() override { return radios.at(0)->tx_end(); }
void tx_end() override
{
// Send Tx exd to all radios
for (auto& r : radios) {
r->tx_end();
}
}
bool rx_now(const uint32_t& radio_idx,
cf_t* buffer[SRSLTE_MAX_PORTS],

@ -114,12 +114,13 @@ extern "C" {
#include "srslte/phy/scrambling/scrambling.h"
#include "srslte/phy/sync/cfo.h"
#include "srslte/phy/sync/cp.h"
#include "srslte/phy/sync/pss.h"
#include "srslte/phy/sync/refsignal_dl_sync.h"
#include "srslte/phy/sync/sfo.h"
#include "srslte/phy/sync/sss.h"
#include "srslte/phy/sync/sync.h"
#include "srslte/phy/sync/cfo.h"
#include "srslte/phy/sync/cp.h"
#ifdef __cplusplus
}

@ -22,17 +22,14 @@
#ifndef SRSLTE_PDCP_H
#define SRSLTE_PDCP_H
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/pdcp_entity.h"
#include "srslte/upper/pdcp_entity_lte.h"
namespace srslte {
class pdcp
:public srsue::pdcp_interface_gw
,public srsue::pdcp_interface_rlc
,public srsue::pdcp_interface_rrc
class pdcp : public srsue::pdcp_interface_rlc, public srsue::pdcp_interface_rrc
{
public:
pdcp(log* log_);
@ -45,29 +42,27 @@ public:
// RRC interface
void reestablish();
void reestablish(uint32_t lcid);
void reestablish(uint32_t lcid);
void reset();
void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, bool blocking = true);
void write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu);
void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, bool blocking = true);
void write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu);
void add_bearer(uint32_t lcid, pdcp_config_t cnfg);
void add_bearer_mrb(uint32_t lcid, pdcp_config_t cnfg);
void del_bearer(uint32_t lcid);
void change_lcid(uint32_t old_lcid, uint32_t new_lcid);
void config_security(uint32_t lcid,
uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_up_enc,
void config_security(uint32_t lcid,
uint8_t* k_rrc_enc,
uint8_t* k_rrc_int,
uint8_t* k_up_enc,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
void config_security_all(uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_up_enc,
void config_security_all(uint8_t* k_rrc_enc,
uint8_t* k_rrc_int,
uint8_t* k_up_enc,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
void enable_integrity(uint32_t lcid);
void enable_encryption(uint32_t lcid);
uint32_t get_dl_count(uint32_t lcid);
uint32_t get_ul_count(uint32_t lcid);
// RLC interface
void write_pdu(uint32_t lcid, unique_byte_buffer_t sdu);
@ -81,11 +76,11 @@ private:
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
typedef std::map<uint16_t, pdcp_entity_interface*> pdcp_map_t;
typedef std::pair<uint16_t, pdcp_entity_interface*> pdcp_map_pair_t;
typedef std::map<uint16_t, pdcp_entity_lte*> pdcp_map_t;
typedef std::pair<uint16_t, pdcp_entity_lte*> pdcp_map_pair_t;
log* pdcp_log = nullptr;
pdcp_map_t pdcp_array, pdcp_array_mrb;
pdcp_map_t pdcp_array, pdcp_array_mrb;
pthread_rwlock_t rwlock;
bool valid_lcid(uint32_t lcid);
@ -93,6 +88,4 @@ private:
};
} // namespace srslte
#endif // SRSLTE_PDCP_H

@ -1,144 +0,0 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_PDCP_ENTITY_H
#define SRSLTE_PDCP_ENTITY_H
#include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include "pdcp_interface.h"
namespace srslte {
/****************************************************************************
* Structs and Defines
* Ref: 3GPP TS 36.323 v10.1.0
***************************************************************************/
#define PDCP_CONTROL_MAC_I 0x00000000
#define PDCP_PDU_TYPE_PDCP_STATUS_REPORT 0x0
#define PDCP_PDU_TYPE_INTERSPERSED_ROHC_FEEDBACK_PACKET 0x1
typedef enum{
PDCP_D_C_CONTROL_PDU = 0,
PDCP_D_C_DATA_PDU,
PDCP_D_C_N_ITEMS,
}pdcp_d_c_t;
static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU",
"Data PDU"};
/****************************************************************************
* PDCP Entity interface
* Common interface for all PDCP entities
***************************************************************************/
class pdcp_entity : public pdcp_entity_interface
{
public:
pdcp_entity();
~pdcp_entity();
void init(srsue::rlc_interface_pdcp *rlc_,
srsue::rrc_interface_pdcp *rrc_,
srsue::gw_interface_pdcp *gw_,
srslte::log *log_,
uint32_t lcid_,
srslte_pdcp_config_t cfg_);
void reset();
void reestablish();
bool is_active();
// RRC interface
void write_sdu(unique_byte_buffer_t sdu, bool blocking);
void config_security(uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
uint8_t *k_up_enc_,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_);
void enable_integrity();
void enable_encryption();
uint32_t get_dl_count();
uint32_t get_ul_count();
// RLC interface
void write_pdu(unique_byte_buffer_t pdu);
private:
byte_buffer_pool* pool = byte_buffer_pool::get_instance();
srslte::log* log = nullptr;
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
bool active = false;
uint32_t lcid = 0;
srslte_pdcp_config_t cfg = {};
uint8_t sn_len_bytes = 0;
bool do_integrity = false;
bool do_encryption = false;
uint32_t rx_count = 0;
uint32_t tx_count = 0;
uint8_t k_rrc_enc[32] = {};
uint8_t k_rrc_int[32] = {};
uint8_t k_up_enc[32] = {};
uint32_t rx_hfn = 0;
uint32_t next_pdcp_rx_sn = 0;
uint32_t reordering_window = 0;
uint32_t last_submitted_pdcp_rx_sn = 0;
uint32_t maximum_pdcp_sn = 0;
CIPHERING_ALGORITHM_ID_ENUM cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
INTEGRITY_ALGORITHM_ID_ENUM integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
pthread_mutex_t mutex;
void handle_um_drb_pdu(const srslte::unique_byte_buffer_t& pdu);
void handle_am_drb_pdu(const srslte::unique_byte_buffer_t& pdu);
void integrity_generate(uint8_t* msg, uint32_t msg_len, uint8_t* mac);
bool integrity_verify(uint8_t* msg, uint32_t count, uint32_t msg_len, uint8_t* mac);
void cipher_encrypt(uint8_t* msg, uint32_t msg_len, uint8_t* ct);
void cipher_decrypt(uint8_t* ct, uint32_t count, uint32_t ct_len, uint8_t* msg);
};
/****************************************************************************
* Pack/Unpack helper functions
* Ref: 3GPP TS 36.323 v10.1.0
***************************************************************************/
void pdcp_pack_control_pdu(uint32_t sn, byte_buffer_t *sdu);
void pdcp_unpack_control_pdu(byte_buffer_t *sdu, uint32_t *sn);
void pdcp_pack_data_pdu_short_sn(uint32_t sn, byte_buffer_t *sdu);
void pdcp_unpack_data_pdu_short_sn(byte_buffer_t *sdu, uint32_t *sn);
void pdcp_pack_data_pdu_long_sn(uint32_t sn, byte_buffer_t *sdu);
void pdcp_unpack_data_pdu_long_sn(byte_buffer_t *sdu, uint32_t *sn);
} // namespace srslte
#endif // SRSLTE_PDCP_ENTITY_H

@ -0,0 +1,133 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_PDCP_ENTITY_BASE_H
#define SRSLTE_PDCP_ENTITY_BASE_H
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/ue_interfaces.h"
#include <mutex>
namespace srslte {
/****************************************************************************
* Structs and Defines common to both LTE and NR
* Ref: 3GPP TS 36.323 v10.1.0 and TS 38.323 v15.2.0
***************************************************************************/
#define PDCP_PDU_TYPE_PDCP_STATUS_REPORT 0x0
#define PDCP_PDU_TYPE_INTERSPERSED_ROHC_FEEDBACK_PACKET 0x1
// Maximum supported PDCP SDU size is 9000 bytes.
// See TS 38.323 v15.2.0, section 4.3.1
#define PDCP_MAX_SDU_SIZE 9000
typedef enum {
PDCP_D_C_CONTROL_PDU = 0,
PDCP_D_C_DATA_PDU,
PDCP_D_C_N_ITEMS,
} pdcp_d_c_t;
static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU", "Data PDU"};
/****************************************************************************
* PDCP Entity interface
* Common interface for LTE and NR PDCP entities
***************************************************************************/
class pdcp_entity_base
{
public:
pdcp_entity_base();
virtual ~pdcp_entity_base();
virtual void reset() = 0;
virtual void reestablish() = 0;
bool is_active() { return active; }
bool is_srb() { return cfg.rb_type == PDCP_RB_IS_SRB; }
bool is_drb() { return cfg.rb_type == PDCP_RB_IS_DRB; }
// RRC interface
void enable_integrity() { do_integrity = true; }
void enable_encryption() { do_encryption = true; }
void config_security(uint8_t* k_rrc_enc_,
uint8_t* k_rrc_int_,
uint8_t* k_up_enc_,
uint8_t* k_up_int_, // NR Only, pass nullptr in LTE
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_);
// GW/SDAP/RRC interface
void write_sdu(unique_byte_buffer_t sdu, bool blocking);
// RLC interface
void write_pdu(unique_byte_buffer_t pdu);
// COUNT, HFN and SN helpers
uint32_t HFN(uint32_t count);
uint32_t SN(uint32_t count);
uint32_t COUNT(uint32_t hfn, uint32_t sn);
protected:
srslte::log* log = nullptr;
bool active = false;
uint32_t lcid = 0;
bool do_integrity = false;
bool do_encryption = false;
pdcp_config_t cfg = {1, PDCP_RB_IS_DRB, SECURITY_DIRECTION_DOWNLINK, SECURITY_DIRECTION_UPLINK, PDCP_SN_LEN_12};
std::mutex mutex;
uint8_t k_rrc_enc[32] = {};
uint8_t k_rrc_int[32] = {};
uint8_t k_up_enc[32] = {};
uint8_t k_up_int[32] = {};
CIPHERING_ALGORITHM_ID_ENUM cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
INTEGRITY_ALGORITHM_ID_ENUM integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
void integrity_generate(uint8_t* msg, uint32_t msg_len, uint32_t count, uint8_t* mac);
bool integrity_verify(uint8_t* msg, uint32_t msg_len, uint32_t count, uint8_t* mac);
void cipher_encrypt(uint8_t* msg, uint32_t msg_len, uint32_t count, uint8_t* ct);
void cipher_decrypt(uint8_t* ct, uint32_t ct_len, uint32_t count, uint8_t* msg);
};
inline uint32_t pdcp_entity_base::HFN(uint32_t count)
{
return (count >> cfg.sn_len);
}
inline uint32_t pdcp_entity_base::SN(uint32_t count)
{
return count & (0xFFFFFFFF >> (32 - cfg.sn_len));
}
inline uint32_t pdcp_entity_base::COUNT(uint32_t hfn, uint32_t sn)
{
return (hfn << cfg.sn_len) | sn;
}
} // namespace srslte
#endif // SRSLTE_PDCP_ENTITY_BASE_H

@ -0,0 +1,101 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_PDCP_ENTITY_LTE_H
#define SRSLTE_PDCP_ENTITY_LTE_H
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/pdcp_entity_base.h"
namespace srslte {
/****************************************************************************
* Structs and Defines
* Ref: 3GPP TS 36.323 v10.1.0
***************************************************************************/
#define PDCP_CONTROL_MAC_I 0x00000000
/****************************************************************************
* LTE PDCP Entity
* Class for LTE PDCP entities
***************************************************************************/
class pdcp_entity_lte final : public pdcp_entity_base
{
public:
pdcp_entity_lte();
~pdcp_entity_lte();
void init(srsue::rlc_interface_pdcp* rlc_,
srsue::rrc_interface_pdcp* rrc_,
srsue::gw_interface_pdcp* gw_,
srslte::log* log_,
uint32_t lcid_,
pdcp_config_t cfg_);
void reset();
void reestablish();
// GW/RRC interface
void write_sdu(unique_byte_buffer_t sdu, bool blocking);
uint32_t get_dl_count();
uint32_t get_ul_count();
// RLC interface
void write_pdu(unique_byte_buffer_t pdu);
private:
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
uint32_t rx_count = 0;
uint32_t tx_count = 0;
uint32_t rx_hfn = 0;
uint32_t next_pdcp_rx_sn = 0;
uint32_t reordering_window = 0;
uint32_t last_submitted_pdcp_rx_sn = 0;
uint32_t maximum_pdcp_sn = 0;
void handle_um_drb_pdu(const srslte::unique_byte_buffer_t& pdu);
void handle_am_drb_pdu(const srslte::unique_byte_buffer_t& pdu);
};
/****************************************************************************
* Pack/Unpack helper functions
* Ref: 3GPP TS 36.323 v10.1.0
***************************************************************************/
void pdcp_pack_control_pdu(uint32_t sn, byte_buffer_t* sdu);
void pdcp_unpack_control_pdu(byte_buffer_t* sdu, uint32_t* sn);
void pdcp_pack_data_pdu_short_sn(uint32_t sn, byte_buffer_t* sdu);
void pdcp_unpack_data_pdu_short_sn(byte_buffer_t* sdu, uint32_t* sn);
void pdcp_pack_data_pdu_long_sn(uint32_t sn, byte_buffer_t* sdu);
void pdcp_unpack_data_pdu_long_sn(byte_buffer_t* sdu, uint32_t* sn);
} // namespace srslte
#endif // SRSLTE_PDCP_ENTITY_LTE_H

@ -0,0 +1,84 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_PDCP_ENTITY_NR_H
#define SRSLTE_PDCP_ENTITY_NR_H
#include "pdcp_entity_base.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
namespace srslte {
/****************************************************************************
* NR PDCP Entity
* PDCP entity for 5G NR
***************************************************************************/
class pdcp_entity_nr : public pdcp_entity_base
{
public:
pdcp_entity_nr();
~pdcp_entity_nr();
void init(srsue::rlc_interface_pdcp* rlc_,
srsue::rrc_interface_pdcp* rrc_,
srsue::gw_interface_pdcp* gw_,
srslte::log* log_,
uint32_t lcid_,
pdcp_config_t cfg_);
void reset();
void reestablish();
// RRC interface
void write_sdu(unique_byte_buffer_t sdu, bool blocking);
uint32_t get_dl_count();
uint32_t get_ul_count();
// RLC interface
void write_pdu(unique_byte_buffer_t pdu);
private:
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
// State variables: 3GPP TS 38.323 v15.2.0, section 7.1
uint32_t tx_next = 0; // COUNT value of next SDU to be transmitted.
uint32_t rx_next = 0; // COUNT value of next SDU expected to be received.
uint32_t rx_deliv = 0; // COUNT value of first SDU not delivered to upper layers, but still waited for.
uint32_t rx_reord = 0; // COUNT value following the COUNT value of PDCP Data PDU which triggered t-Reordering.
// Constants: 3GPP TS 38.323 v15.2.0, section 7.2
uint32_t window_size = 0;
// Packing/Unpacking Helper functions
uint32_t read_data_header(const unique_byte_buffer_t& sdu);
void write_data_header(const unique_byte_buffer_t& sdu, uint32_t sn);
void extract_mac(const unique_byte_buffer_t& sdu, uint8_t* mac);
void append_mac(const unique_byte_buffer_t& sdu, uint8_t* mac);
};
} // namespace srslte
#endif // SRSLTE_PDCP_ENTITY_NR_H

@ -1,71 +0,0 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_PDCP_INTERFACE_H
#define SRSLTE_PDCP_INTERFACE_H
#include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
namespace srslte {
/****************************************************************************
* Virtual PDCP interface common for all PDCP entities
***************************************************************************/
class pdcp_entity_interface
{
public:
virtual ~pdcp_entity_interface() {};
virtual void init(srsue::rlc_interface_pdcp *rlc_,
srsue::rrc_interface_pdcp *rrc_,
srsue::gw_interface_pdcp *gw_,
srslte::log *log_,
uint32_t lcid_,
srslte_pdcp_config_t cfg_) = 0;
virtual void reset() = 0;
virtual void reestablish() = 0;
virtual bool is_active() = 0;
// RRC interface
virtual void write_sdu(unique_byte_buffer_t sdu, bool blocking) = 0;
virtual void config_security(uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
uint8_t *k_up_enc_,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void enable_integrity() = 0;
virtual void enable_encryption() = 0;
virtual uint32_t get_dl_count() = 0;
virtual uint32_t get_ul_count() = 0;
// RLC interface
virtual void write_pdu(unique_byte_buffer_t pdu) = 0;
};
} // namespace srslte
#endif // SRSLTE_PDCP_INTERFACE_H

@ -45,13 +45,10 @@ class rlc
public:
rlc(log* rlc_log_);
virtual ~rlc();
void init(srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
mac_interface_timers* mac_timers_,
uint32_t lcid_);
void init(srsue::pdcp_interface_rlc* pdcp_, srsue::rrc_interface_rlc* rrc_, srslte::timers* timers_, uint32_t lcid_);
void stop();
void get_metrics(rlc_metrics_t &m);
void get_metrics(rlc_metrics_t& m);
// PDCP interface
void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, bool blocking = true);
@ -92,9 +89,9 @@ private:
srslte::log* rlc_log = nullptr;
srsue::pdcp_interface_rlc* pdcp = nullptr;
srsue::rrc_interface_rlc* rrc = nullptr;
srslte::mac_interface_timers* mac_timers = nullptr;
srslte::timers* timers = nullptr;
typedef std::map<uint16_t, rlc_common*> rlc_map_t;
typedef std::map<uint16_t, rlc_common*> rlc_map_t;
typedef std::pair<uint16_t, rlc_common*> rlc_map_pair_t;
rlc_map_t rlc_array, rlc_array_mrb;
@ -109,7 +106,6 @@ private:
bool valid_lcid_mrb(uint32_t lcid);
};
} // namespace srsue
} // namespace srslte
#endif // SRSLTE_RLC_H

@ -64,12 +64,11 @@ struct rlc_amd_retx_t{
class rlc_am : public rlc_common
{
public:
rlc_am(srslte::log* log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srslte::mac_interface_timers* mac_timers_);
~rlc_am();
rlc_am(srslte::log* log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srslte::timers* timers_);
bool configure(rlc_config_t cfg_);
void reestablish();
void stop();
@ -223,7 +222,7 @@ private:
void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header);
void handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header);
void reassemble_rx_sdus();
bool inside_rx_window(uint16_t sn);
bool inside_rx_window(const int16_t sn);
void debug_state();
void print_rx_segments();
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment);
@ -276,13 +275,13 @@ private:
};
// Common variables needed/provided by parent class
srsue::rrc_interface_rlc* rrc = nullptr;
srslte::log* log = nullptr;
srsue::pdcp_interface_rlc* pdcp = nullptr;
mac_interface_timers* mac_timers = nullptr;
uint32_t lcid = 0;
rlc_config_t cfg = {};
std::string rb_name;
srsue::rrc_interface_rlc* rrc = nullptr;
srslte::log* log = nullptr;
srsue::pdcp_interface_rlc* pdcp = nullptr;
srslte::timers* timers = nullptr;
uint32_t lcid = 0;
rlc_config_t cfg = {};
std::string rb_name;
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
@ -307,6 +306,7 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t *status, uint8_t *payload);
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header);
uint32_t rlc_am_packed_length(rlc_status_pdu_t *status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status);
bool rlc_am_is_control_pdu(byte_buffer_t *pdu);
bool rlc_am_is_control_pdu(uint8_t *payload);
bool rlc_am_is_pdu_segment(uint8_t *payload);
@ -319,5 +319,4 @@ bool rlc_am_not_start_aligned(const uint8_t fi);
} // namespace srslte
#endif // SRSLTE_RLC_AM_H

@ -48,6 +48,28 @@ static const char rlc_fi_field_text[RLC_FI_FIELD_N_ITEMS][32] = {"Start and end
"Not start aligned",
"Not start or end aligned"};
enum class rlc_nr_si_field_t : unsigned {
full_sdu = 0b00,
first_segment = 0b01,
last_segment = 0b10,
neither_first_nor_last_segment = 0b11,
nulltype
};
inline std::string to_string(const rlc_nr_si_field_t& si)
{
constexpr static const char* options[] = {"Data field contains full SDU",
"Data field contains first segment of SDU",
"Data field contains last segment of SDU",
"Data field contains neither first nor last segment of SDU"};
return enum_to_text(options, (uint32_t)rlc_nr_si_field_t::nulltype, (uint32_t)si);
}
static inline uint8_t operator&(rlc_nr_si_field_t lhs, int rhs)
{
return static_cast<uint8_t>(static_cast<std::underlying_type<rlc_nr_si_field_t>::type>(lhs) &
static_cast<std::underlying_type<rlc_nr_si_field_t>::type>(rhs));
}
typedef enum{
RLC_DC_FIELD_CONTROL_PDU = 0,
RLC_DC_FIELD_DATA_PDU,
@ -65,6 +87,13 @@ typedef struct{
uint16_t li[RLC_AM_WINDOW_SIZE]; // Array of length indicators
}rlc_umd_pdu_header_t;
typedef struct {
rlc_nr_si_field_t si; // Segmentation info
rlc_um_nr_sn_size_t sn_size; // Sequence number size (6 or 12 bits)
uint16_t sn; // Sequence number
uint16_t so; // Sequence offset
} rlc_um_nr_pdu_header_t;
// AMD PDU Header
struct rlc_amd_pdu_header_t{
rlc_dc_field_t dc; // Data or control
@ -125,7 +154,7 @@ struct rlc_status_nack_t{
// STATUS PDU
struct rlc_status_pdu_t{
uint16_t ack_sn;
uint16_t ack_sn; // SN of the next not received RLC Data PDU
uint32_t N_nack;
rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE];

@ -34,12 +34,12 @@ namespace srslte {
class rlc_tm : public rlc_common
{
public:
rlc_tm(srslte::log* log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srslte::mac_interface_timers* mac_timers_,
uint32_t queue_len = 16);
rlc_tm(srslte::log* log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srslte::timers* timers_,
uint32_t queue_len = 16);
~rlc_tm();
bool configure(rlc_config_t cnfg);
void stop();
@ -78,7 +78,6 @@ private:
rlc_tx_queue ul_queue;
};
} // namespace srsue
} // namespace srslte
#endif // SRSLTE_RLC_TM_H

@ -23,13 +23,14 @@
#define SRSLTE_RLC_UM_H
#include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/rlc_tx_queue.h"
#include "srslte/upper/rlc_common.h"
#include <pthread.h>
#include "srslte/upper/rlc_tx_queue.h"
#include <map>
#include <mutex>
#include <pthread.h>
#include <queue>
namespace srslte {
@ -39,6 +40,11 @@ struct rlc_umd_pdu_t{
unique_byte_buffer_t buf;
};
typedef struct {
rlc_um_nr_pdu_header_t header;
unique_byte_buffer_t buf;
} rlc_umd_pdu_nr_t;
class rlc_um
:public rlc_common
{
@ -47,7 +53,7 @@ public:
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
mac_interface_timers* mac_timers_);
srslte::timers* timers_);
~rlc_um();
bool configure(rlc_config_t cnfg);
void reestablish();
@ -73,14 +79,13 @@ public:
void reset_metrics();
private:
// Transmitter sub-class
class rlc_um_tx
// Transmitter sub-class base
class rlc_um_tx_base
{
public:
rlc_um_tx(srslte::log* log_);
~rlc_um_tx();
bool configure(rlc_config_t cfg, std::string rb_name);
rlc_um_tx_base(srslte::log* log_);
virtual ~rlc_um_tx_base();
virtual bool configure(rlc_config_t cfg, std::string rb_name) = 0;
int build_data_pdu(uint8_t *payload, uint32_t nof_bytes);
void stop();
void reestablish();
@ -92,7 +97,7 @@ private:
bool has_data();
uint32_t get_buffer_state();
private:
protected:
byte_buffer_pool* pool = nullptr;
srslte::log* log = nullptr;
std::string rb_name;
@ -101,41 +106,71 @@ private:
* Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
rlc_um_config_t cfg = {};
rlc_config_t cfg = {};
// TX SDU buffers
rlc_tx_queue tx_sdu_queue;
unique_byte_buffer_t tx_sdu;
// Mutexes
std::mutex mutex;
bool tx_enabled = false;
uint32_t num_tx_bytes = 0;
virtual int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes) = 0;
// helper functions
virtual void debug_state() = 0;
const char* get_rb_name();
};
// Transmitter sub-class for LTE
class rlc_um_tx : public rlc_um_tx_base
{
public:
rlc_um_tx(srslte::log* log_);
bool configure(rlc_config_t cfg, std::string rb_name);
int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes);
private:
/****************************************************************************
* State variables and counters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
uint32_t vt_us = 0; // Send state. SN to be assigned for next PDU.
// Mutexes
pthread_mutex_t mutex;
void debug_state();
};
bool tx_enabled = false;
// Transmitter sub-class for NR
class rlc_um_tx_nr : public rlc_um_tx_base
{
public:
rlc_um_tx_nr(srslte::log* log_);
uint32_t num_tx_bytes = 0;
bool configure(rlc_config_t cfg, std::string rb_name);
int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes);
private:
uint32_t TX_Next = 0; // send state as defined in TS 38.322 v15.3 Section 7
// helper functions
void debug_state();
const char* get_rb_name();
};
// Receiver sub-class
class rlc_um_rx : public timer_callback {
public:
rlc_um_rx(srslte::log* log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srslte::mac_interface_timers* mac_timers_);
rlc_um_rx(srslte::log* log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srslte::timers* timers_);
~rlc_um_rx();
void stop();
void reestablish();
void stop();
void reestablish();
bool configure(rlc_config_t cfg, std::string rb_name);
void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes);
void reassemble_rx_sdus();
@ -150,16 +185,16 @@ private:
private:
void reset();
byte_buffer_pool* pool = nullptr;
srslte::log* log = nullptr;
mac_interface_timers* mac_timers = nullptr;
std::string rb_name;
byte_buffer_pool* pool = nullptr;
srslte::log* log = nullptr;
srslte::timers* timers = nullptr;
std::string rb_name;
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
rlc_um_config_t cfg = {};
rlc_config_t cfg = {};
// Rx window
std::map<uint32_t, rlc_umd_pdu_t> rx_window;
@ -182,7 +217,7 @@ private:
uint32_t lcid = 0;
// Mutexes
pthread_mutex_t mutex;
std::mutex mutex;
bool rx_enabled = false;
@ -209,7 +244,7 @@ private:
std::string get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb);
// Rx and Tx objects
rlc_um_tx tx;
std::unique_ptr<rlc_um_tx_base> tx;
rlc_um_rx rx;
};
@ -225,7 +260,23 @@ uint32_t rlc_um_packed_length(rlc_umd_pdu_header_t *header);
bool rlc_um_start_aligned(uint8_t fi);
bool rlc_um_end_aligned(uint8_t fi);
} // namespace srsue
/****************************************************************************
* Header pack/unpack helper functions for NR
* Ref: 3GPP TS 38.322 v15.3.0 Section 6.2.2.3
***************************************************************************/
uint32_t rlc_um_nr_read_data_pdu_header(const byte_buffer_t* pdu,
const rlc_um_nr_sn_size_t sn_size,
rlc_um_nr_pdu_header_t* header);
uint32_t rlc_um_nr_read_data_pdu_header(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_um_nr_sn_size_t sn_size,
rlc_um_nr_pdu_header_t* header);
uint32_t rlc_um_nr_write_data_pdu_header(const rlc_um_nr_pdu_header_t& header, byte_buffer_t* pdu);
uint32_t rlc_um_nr_packed_length(const rlc_um_nr_pdu_header_t& header);
} // namespace srslte
#endif // SRSLTE_RLC_UM_H

@ -83,16 +83,6 @@ void log_error_code(SRSASN_CODE code, const char* filename, int line)
bit_ref
*********************/
bit_ref::bit_ref() : ptr(NULL), offset(0), start_ptr(NULL), max_ptr(NULL) {}
bit_ref::bit_ref(uint8_t* start_ptr_, uint32_t max_size_) :
ptr(start_ptr_),
offset(0),
start_ptr(start_ptr_),
max_ptr(max_size_ + start_ptr_)
{
}
int bit_ref::distance(const bit_ref& other) const
{
return ((int)offset - (int)other.offset) + 8 * ((int)(ptr - other.ptr));
@ -116,6 +106,10 @@ int bit_ref::distance_bytes() const
SRSASN_CODE bit_ref::pack(uint32_t val, uint32_t n_bits)
{
if (n_bits >= 32) {
srsasn_log_print(LOG_LEVEL_ERROR, "This method only supports packing up to 32 bits\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
uint32_t mask;
while (n_bits > 0) {
if (ptr >= max_ptr) {
@ -141,8 +135,33 @@ SRSASN_CODE bit_ref::pack(uint32_t val, uint32_t n_bits)
return SRSASN_SUCCESS;
}
SRSASN_CODE bit_ref::pack_bytes(const uint8_t* buf, uint32_t n_bytes)
{
if (n_bytes == 0) {
return SRSASN_SUCCESS;
}
if (ptr + n_bytes >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
if (offset == 0) {
// Aligned case
memcpy(ptr, buf, n_bytes);
ptr += n_bytes;
} else {
for (uint32_t i = 0; i < n_bytes; ++i) {
pack(buf[i], 8);
}
}
return SRSASN_SUCCESS;
}
ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_t n_bits)
{
if (n_bits > 32) {
srsasn_log_print(LOG_LEVEL_ERROR, "This method only supports unpacking up to 32 bits\n");
return {0, SRSASN_ERROR_DECODE_FAIL};
}
uint32_t val = 0;
while (n_bits > 0) {
if (ptr >= max_ptr) {
@ -165,6 +184,27 @@ ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_
return ValOrError(val, SRSASN_SUCCESS);
}
SRSASN_CODE bit_ref::unpack_bytes(uint8_t* buf, uint32_t n_bytes)
{
if (n_bytes == 0) {
return SRSASN_SUCCESS;
}
if (ptr + n_bytes >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_DECODE_FAIL;
}
if (offset == 0) {
// Aligned case
memcpy(buf, ptr, n_bytes);
ptr += n_bytes;
} else {
for (uint32_t i = 0; i < n_bytes; ++i) {
unpack(buf[i], 8);
}
}
return SRSASN_SUCCESS;
}
SRSASN_CODE bit_ref::align_bytes()
{
if (offset == 0)
@ -193,6 +233,21 @@ SRSASN_CODE bit_ref::align_bytes_zero()
return SRSASN_SUCCESS;
}
SRSASN_CODE bit_ref::advance_bits(uint32_t n_bits)
{
uint32_t extra_bits = (offset + n_bits) % 8;
uint32_t bytes_required = ceilf((offset + n_bits) / 8.0f);
uint32_t bytes_offset = floorf((offset + n_bits) / 8.0f);
if (ptr + bytes_required >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_DECODE_FAIL;
}
ptr += bytes_offset;
offset = extra_bits;
return SRSASN_SUCCESS;
}
void bit_ref::set(uint8_t* start_ptr_, uint32_t max_size_)
{
ptr = start_ptr_;
@ -370,10 +425,6 @@ template SRSASN_CODE unpack_unalign_integer<uint16_t>(uint16_t& n, bit_ref& bref
template SRSASN_CODE unpack_unalign_integer<uint32_t>(uint32_t& n, bit_ref& bref, uint32_t lb, uint32_t ub);
template SRSASN_CODE unpack_unalign_integer<uint64_t>(uint64_t& n, bit_ref& bref, uint64_t lb, uint64_t ub);
template <class IntType>
UnalignedIntegerPacker<IntType>::UnalignedIntegerPacker(IntType lb_, IntType ub_) : lb(lb_), ub(ub_)
{
}
template <class IntType>
SRSASN_CODE UnalignedIntegerPacker<IntType>::pack(bit_ref& bref, IntType n) const
{
@ -921,86 +972,83 @@ void log_invalid_choice_id(uint32_t val, const char* choice_type)
ext group
*********************/
ext_groups_header::ext_groups_header(uint32_t max_nof_groups, uint32_t nof_nogroups_) : nof_nogroups(nof_nogroups_)
bool& ext_groups_packer_guard::operator[](uint32_t idx)
{
if (max_nof_groups > 20) {
srsasn_log_print(LOG_LEVEL_ERROR, "increase the size of ext group packer/unpacker\n");
}
groups.resize(max_nof_groups);
for (uint32_t i = 0; i < groups.size(); ++i) {
groups[i] = false;
if (idx >= groups.size()) {
uint32_t prev_size = groups.size();
groups.resize(idx + 1);
std::fill(&groups[prev_size], &groups[groups.size()], false);
}
nof_groups = groups.size() + 1; // unset
}
bool& ext_groups_header::operator[](uint32_t idx)
{
return groups[idx];
}
SRSASN_CODE ext_groups_header::pack_nof_groups(bit_ref& bref) const
SRSASN_CODE ext_groups_packer_guard::pack(asn1::bit_ref& bref) const
{
nof_groups = 0;
for (uint32_t i = 0; i < groups.size(); ++i) {
// pack number of groups
int32_t i = groups.size() - 1;
for (; i >= 0; --i) {
if (groups[i]) {
nof_groups = i + 1;
break;
}
}
if (nof_groups > groups.size()) {
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size());
return SRSASN_ERROR_ENCODE_FAIL;
uint32_t nof_groups = (uint32_t)i + 1u;
HANDLE_CODE(pack_norm_small_integer(bref, nof_groups - 1));
// pack each group presence flag
for (uint32_t j = 0; j < nof_groups; ++j) {
HANDLE_CODE(bref.pack(groups[j], 1));
}
HANDLE_CODE(pack_norm_small_integer(bref, nof_groups + nof_nogroups - 1));
return SRSASN_SUCCESS;
}
SRSASN_CODE ext_groups_header::pack_group_flags(bit_ref& bref) const
ext_groups_unpacker_guard::ext_groups_unpacker_guard(uint32_t nof_supported_groups_) :
nof_supported_groups(nof_supported_groups_)
{
if (nof_groups > groups.size()) {
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size());
return SRSASN_ERROR_ENCODE_FAIL;
}
for (uint32_t i = 0; i < nof_groups; ++i) {
HANDLE_CODE(bref.pack(groups[i], 1));
resize(nof_supported_groups);
}
bool& ext_groups_unpacker_guard::operator[](uint32_t idx)
{
if (idx >= groups.size()) {
// only resizes for unknown extensions
resize(idx + 1);
}
return SRSASN_SUCCESS;
return groups[idx];
}
SRSASN_CODE ext_groups_header::pack(bit_ref& bref) const
void ext_groups_unpacker_guard::resize(uint32_t new_size)
{
HANDLE_CODE(pack_nof_groups(bref));
return pack_group_flags(bref);
// always grows
uint32_t prev_size = groups.size();
groups.resize(std::max(new_size, nof_supported_groups));
std::fill(&groups[prev_size], &groups[groups.size()], false);
}
SRSASN_CODE ext_groups_header::unpack_nof_groups(bit_ref& bref)
ext_groups_unpacker_guard::~ext_groups_unpacker_guard()
{
HANDLE_CODE(unpack_norm_small_integer(nof_groups, bref));
nof_groups += 1 - nof_nogroups;
if (nof_groups > groups.size()) {
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size());
return SRSASN_ERROR_DECODE_FAIL;
// consume all the unknown extensions
for (uint32_t i = nof_supported_groups; i < nof_unpacked_groups; ++i) {
if (groups[i]) {
varlength_field_unpack_guard scope(*bref_tracker);
}
}
return SRSASN_SUCCESS;
}
SRSASN_CODE ext_groups_header::unpack_group_flags(bit_ref& bref)
SRSASN_CODE ext_groups_unpacker_guard::unpack(bit_ref& bref)
{
if (nof_groups > groups.size()) {
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size());
return SRSASN_ERROR_DECODE_FAIL;
}
for (uint32_t i = 0; i < nof_groups; ++i) {
bref_tracker = &bref;
// unpack nof of ext groups
HANDLE_CODE(unpack_norm_small_integer(nof_unpacked_groups, bref));
nof_unpacked_groups += 1;
resize(nof_unpacked_groups);
// unpack each group presence flag
for (uint32_t i = 0; i < nof_unpacked_groups; ++i) {
HANDLE_CODE(bref.unpack(groups[i], 1));
}
return SRSASN_SUCCESS;
}
SRSASN_CODE ext_groups_header::unpack(bit_ref& bref)
{
HANDLE_CODE(unpack_nof_groups(bref));
return unpack_group_flags(bref);
}
/*********************
Open Field
*********************/

@ -6433,12 +6433,27 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_request_msg(LIBLTE_BYTE_MSG_STRUCT*
Document Reference: 24.301 v10.2.0 Section 8.2.19
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT* msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8* msg_ptr = msg->msg;
if (id_resp != NULL && msg != NULL) {
if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) {
// Protocol Discriminator and Security Header Type
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++;
// MAC will be filled in later
msg_ptr += 4;
// Sequence Number
*msg_ptr = count & 0xFF;
msg_ptr++;
}
// Protocol Discriminator and Security Header Type
*msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++;

File diff suppressed because it is too large Load Diff

@ -26,8 +26,8 @@ using namespace asn1;
using namespace asn1::rrc;
/*******************************************************************************
/* Helper Functions
/******************************************************************************/
* Helper Functions
******************************************************************************/
static void invalid_enum_number(int value, const char* name)
{
@ -36,8 +36,8 @@ static void invalid_enum_number(int value, const char* name)
}
/*******************************************************************************
/* Struct Methods
/******************************************************************************/
* Struct Methods
******************************************************************************/
std::string phich_cfg_s::phich_dur_opts::to_string() const
{

@ -74,6 +74,32 @@ void to_asn1(asn1::rrc::s_tmsi_s* asn1_type, const s_tmsi_t& cfg)
asn1_type->m_tmsi.from_number(cfg.m_tmsi);
}
/***************************
* CQI Report Aperiodic
**************************/
srslte_cqi_report_mode_t make_aperiodic_mode(const asn1::rrc::cqi_report_mode_aperiodic_e asn_mode)
{
switch (asn_mode) {
case asn1::rrc::cqi_report_mode_aperiodic_e::rm12:
return SRSLTE_CQI_MODE_12;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm20:
return SRSLTE_CQI_MODE_20;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm22:
return SRSLTE_CQI_MODE_22;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm30:
return SRSLTE_CQI_MODE_30;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm31:
return SRSLTE_CQI_MODE_31;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm10_v1310:
case asn1::rrc::cqi_report_mode_aperiodic_e::rm11_v1310:
case asn1::rrc::cqi_report_mode_aperiodic_e::rm32_v1250:
fprintf(stderr, "Aperiodic mode %s not handled\n", asn_mode.to_string().c_str());
default:
return SRSLTE_CQI_MODE_NA;
}
}
/***************************
* Establishment Cause
**************************/
@ -155,4 +181,601 @@ void to_asn1(asn1::rrc::rlc_cfg_c* asn1_type, const srslte::rlc_config_t& cfg)
}
/***************************
* MAC Config
**************************/
void set_mac_cfg_t_sched_request_cfg(mac_cfg_t* cfg, const asn1::rrc::sched_request_cfg_c& asn1_type)
{
cfg->sr_cfg.enabled = asn1_type.type() == asn1::rrc::setup_e::setup;
if (cfg->sr_cfg.enabled) {
cfg->sr_cfg.dsr_transmax = asn1_type.setup().dsr_trans_max.to_number();
}
}
// MAC-MainConfig section is always present
void set_mac_cfg_t_main_cfg(mac_cfg_t* cfg, const asn1::rrc::mac_main_cfg_s& asn1_type)
{
// Update values only if each section is present
if (asn1_type.phr_cfg_present) {
cfg->phr_cfg.enabled = asn1_type.phr_cfg.type() == asn1::rrc::setup_e::setup;
if (cfg->phr_cfg.enabled) {
cfg->phr_cfg.prohibit_timer = asn1_type.phr_cfg.setup().prohibit_phr_timer.to_number();
cfg->phr_cfg.periodic_timer = asn1_type.phr_cfg.setup().periodic_phr_timer.to_number();
cfg->phr_cfg.db_pathloss_change = asn1_type.phr_cfg.setup().dl_pathloss_change.to_number();
}
}
if (asn1_type.mac_main_cfg_v1020.is_present()) {
cfg->phr_cfg.extended = asn1_type.mac_main_cfg_v1020.get()->extended_phr_r10_present;
}
if (asn1_type.ul_sch_cfg_present) {
cfg->bsr_cfg.periodic_timer = asn1_type.ul_sch_cfg.periodic_bsr_timer.to_number();
cfg->bsr_cfg.retx_timer = asn1_type.ul_sch_cfg.retx_bsr_timer.to_number();
if (asn1_type.ul_sch_cfg.max_harq_tx_present) {
cfg->harq_cfg.max_harq_tx = asn1_type.ul_sch_cfg.max_harq_tx.to_number();
}
}
// TimeAlignmentDedicated overwrites Common??
cfg->time_alignment_timer = asn1_type.time_align_timer_ded.to_number();
}
// RACH-Common section is always present
void set_mac_cfg_t_rach_cfg_common(mac_cfg_t* cfg, const asn1::rrc::rach_cfg_common_s& asn1_type)
{
// Preamble info
cfg->rach_cfg.nof_preambles = asn1_type.preamb_info.nof_ra_preambs.to_number();
if (asn1_type.preamb_info.preambs_group_a_cfg_present) {
cfg->rach_cfg.nof_groupA_preambles =
asn1_type.preamb_info.preambs_group_a_cfg.size_of_ra_preambs_group_a.to_number();
cfg->rach_cfg.messageSizeGroupA = asn1_type.preamb_info.preambs_group_a_cfg.msg_size_group_a.to_number();
cfg->rach_cfg.messagePowerOffsetGroupB =
asn1_type.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number();
} else {
cfg->rach_cfg.nof_groupA_preambles = 0;
}
// Power ramping
cfg->rach_cfg.powerRampingStep = asn1_type.pwr_ramp_params.pwr_ramp_step.to_number();
cfg->rach_cfg.iniReceivedTargetPower = asn1_type.pwr_ramp_params.preamb_init_rx_target_pwr.to_number();
// Supervision info
cfg->rach_cfg.preambleTransMax = asn1_type.ra_supervision_info.preamb_trans_max.to_number();
cfg->rach_cfg.responseWindowSize = asn1_type.ra_supervision_info.ra_resp_win_size.to_number();
cfg->rach_cfg.contentionResolutionTimer = asn1_type.ra_supervision_info.mac_contention_resolution_timer.to_number();
// HARQ Msg3
cfg->harq_cfg.max_harq_msg3_tx = asn1_type.max_harq_msg3_tx;
}
void set_mac_cfg_t_time_alignment(mac_cfg_t* cfg, const asn1::rrc::time_align_timer_opts asn1_type)
{
cfg->time_alignment_timer = asn1_type.to_number();
}
void set_phy_cfg_t_dedicated_cfg(phy_cfg_t* cfg, const asn1::rrc::phys_cfg_ded_s& asn1_type)
{
if (asn1_type.pucch_cfg_ded_present) {
if (asn1_type.pucch_cfg_ded.tdd_ack_nack_feedback_mode_present) {
cfg->ul_cfg.pucch.tdd_ack_multiplex = asn1_type.pucch_cfg_ded.tdd_ack_nack_feedback_mode ==
asn1::rrc::pucch_cfg_ded_s::tdd_ack_nack_feedback_mode_e_::mux;
} else {
cfg->ul_cfg.pucch.tdd_ack_multiplex = false;
}
}
if (asn1_type.pucch_cfg_ded_v1020.is_present()) {
auto* pucch_cfg_ded = asn1_type.pucch_cfg_ded_v1020.get();
if (pucch_cfg_ded->pucch_format_r10_present) {
typedef asn1::rrc::pucch_cfg_ded_v1020_s::pucch_format_r10_c_ pucch_format_r10_t;
auto* pucch_format_r10 = &pucch_cfg_ded->pucch_format_r10;
if (pucch_format_r10->type() == pucch_format_r10_t::types::format3_r10) {
// Select feedback mode
cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3;
auto* format3_r13 = &pucch_format_r10->format3_r10();
for (uint32_t n = 0; n < SRSLTE_MIN(format3_r13->n3_pucch_an_list_r13.size(), SRSLTE_PUCCH_SIZE_AN_CS); n++) {
cfg->ul_cfg.pucch.n3_pucch_an_list[n] = format3_r13->n3_pucch_an_list_r13[n];
}
if (format3_r13->two_ant_port_activ_pucch_format3_r13_present) {
if (format3_r13->two_ant_port_activ_pucch_format3_r13.type() == asn1::rrc::setup_e::setup) {
// TODO: UL MIMO Configure PUCCH two antenna port
} else {
// TODO: UL MIMO Disable two antenna port
}
}
} else if (pucch_format_r10->type() == asn1::rrc::pucch_cfg_ded_v1020_s::pucch_format_r10_c_::types::ch_sel_r10) {
typedef pucch_format_r10_t::ch_sel_r10_s_ ch_sel_r10_t;
auto* ch_sel_r10 = &pucch_format_r10->ch_sel_r10();
if (ch_sel_r10->n1_pucch_an_cs_r10_present) {
typedef ch_sel_r10_t::n1_pucch_an_cs_r10_c_ n1_pucch_an_cs_r10_t;
auto* n1_pucch_an_cs_r10 = &ch_sel_r10->n1_pucch_an_cs_r10;
if (n1_pucch_an_cs_r10->type() == asn1::rrc::setup_e::setup) {
// Select feedback mode
cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS;
typedef n1_pucch_an_cs_r10_t::setup_s_::n1_pucch_an_cs_list_r10_l_ n1_pucch_an_cs_list_r10_t;
n1_pucch_an_cs_list_r10_t n1_pucch_an_cs_list =
ch_sel_r10->n1_pucch_an_cs_r10.setup().n1_pucch_an_cs_list_r10;
for (uint32_t i = 0; i < SRSLTE_MIN(n1_pucch_an_cs_list.size(), SRSLTE_PUCCH_NOF_AN_CS); i++) {
asn1::rrc::n1_pucch_an_cs_r10_l n1_pucch_an_cs = n1_pucch_an_cs_list[i];
for (uint32_t j = 0; j < SRSLTE_PUCCH_SIZE_AN_CS; j++) {
cfg->ul_cfg.pucch.n1_pucch_an_cs[j][i] = n1_pucch_an_cs[j];
}
}
} else {
cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL;
}
}
} else {
// Do nothing
}
}
}
if (asn1_type.pusch_cfg_ded_present) {
cfg->ul_cfg.pusch.uci_offset.I_offset_ack = asn1_type.pusch_cfg_ded.beta_offset_ack_idx;
cfg->ul_cfg.pusch.uci_offset.I_offset_cqi = asn1_type.pusch_cfg_ded.beta_offset_cqi_idx;
cfg->ul_cfg.pusch.uci_offset.I_offset_ri = asn1_type.pusch_cfg_ded.beta_offset_ri_idx;
}
if (asn1_type.ul_pwr_ctrl_ded_present) {
cfg->ul_cfg.power_ctrl.p0_ue_pusch = asn1_type.ul_pwr_ctrl_ded.p0_ue_pusch;
cfg->ul_cfg.power_ctrl.delta_mcs_based =
asn1_type.ul_pwr_ctrl_ded.delta_mcs_enabled == asn1::rrc::ul_pwr_ctrl_ded_s::delta_mcs_enabled_e_::en0;
cfg->ul_cfg.power_ctrl.acc_enabled = asn1_type.ul_pwr_ctrl_ded.accumulation_enabled;
cfg->ul_cfg.power_ctrl.p0_ue_pucch = asn1_type.ul_pwr_ctrl_ded.p0_ue_pucch;
cfg->ul_cfg.power_ctrl.p_srs_offset = asn1_type.ul_pwr_ctrl_ded.p_srs_offset;
}
if (asn1_type.ul_pwr_ctrl_ded.filt_coef_present) {
// TODO
}
if (asn1_type.tpc_pdcch_cfg_pucch_present) {
// TODO
}
if (asn1_type.tpc_pdcch_cfg_pusch_present) {
// TODO
}
if (asn1_type.cqi_report_cfg_present) {
if (asn1_type.cqi_report_cfg.cqi_report_periodic_present) {
cfg->dl_cfg.cqi_report.periodic_configured =
asn1_type.cqi_report_cfg.cqi_report_periodic.type() == asn1::rrc::setup_e::setup;
if (cfg->dl_cfg.cqi_report.periodic_configured) {
cfg->ul_cfg.pucch.n_pucch_2 = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx;
cfg->ul_cfg.pucch.simul_cqi_ack = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi;
cfg->dl_cfg.cqi_report.pmi_idx = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx;
cfg->dl_cfg.cqi_report.format_is_subband =
asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.type().value ==
asn1::rrc::cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::subband_cqi;
if (cfg->dl_cfg.cqi_report.format_is_subband) {
cfg->dl_cfg.cqi_report.subband_size =
asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.subband_cqi().k;
}
if (asn1_type.cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present) {
cfg->dl_cfg.cqi_report.ri_idx = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx;
cfg->dl_cfg.cqi_report.ri_idx_present = true;
} else {
cfg->dl_cfg.cqi_report.ri_idx_present = false;
}
} else {
cfg->ul_cfg.pucch.n_pucch_2 = 0;
cfg->ul_cfg.pucch.simul_cqi_ack = false;
}
}
if (asn1_type.cqi_report_cfg.cqi_report_mode_aperiodic_present) {
cfg->dl_cfg.cqi_report.aperiodic_configured = true;
cfg->dl_cfg.cqi_report.aperiodic_mode = make_aperiodic_mode(asn1_type.cqi_report_cfg.cqi_report_mode_aperiodic);
}
}
if (asn1_type.cqi_report_cfg_pcell_v1250.is_present()) {
auto cqi_report_cfg_pcell_v1250 = asn1_type.cqi_report_cfg_pcell_v1250.get();
if (cqi_report_cfg_pcell_v1250->alt_cqi_table_r12_present) {
cfg->dl_cfg.pdsch.use_tbs_index_alt = true;
}
} else {
cfg->dl_cfg.pdsch.use_tbs_index_alt = false;
}
if (asn1_type.srs_ul_cfg_ded_present) {
cfg->ul_cfg.srs.dedicated_enabled = asn1_type.srs_ul_cfg_ded.type() == asn1::rrc::setup_e::setup;
if (cfg->ul_cfg.srs.dedicated_enabled) {
cfg->ul_cfg.srs.configured = cfg->ul_cfg.srs.dedicated_enabled and cfg->ul_cfg.srs.common_enabled;
cfg->ul_cfg.srs.I_srs = asn1_type.srs_ul_cfg_ded.setup().srs_cfg_idx;
cfg->ul_cfg.srs.B = asn1_type.srs_ul_cfg_ded.setup().srs_bw;
cfg->ul_cfg.srs.b_hop = asn1_type.srs_ul_cfg_ded.setup().srs_hop_bw;
cfg->ul_cfg.srs.n_rrc = asn1_type.srs_ul_cfg_ded.setup().freq_domain_position;
cfg->ul_cfg.srs.k_tc = asn1_type.srs_ul_cfg_ded.setup().tx_comb;
cfg->ul_cfg.srs.n_srs = asn1_type.srs_ul_cfg_ded.setup().cyclic_shift;
}
}
if (asn1_type.ant_info_r10.is_present() &&
asn1_type.ant_info_r10->type() == asn1::rrc::phys_cfg_ded_s::ant_info_r10_c_::types::explicit_value_r10) {
// Parse Release 10
asn1::rrc::ant_info_ded_r10_s::tx_mode_r10_e_::options tx_mode =
asn1_type.ant_info_r10->explicit_value_r10().tx_mode_r10.value;
if ((srslte_tm_t)tx_mode < SRSLTE_TMINV) {
cfg->dl_cfg.tm = (srslte_tm_t)tx_mode;
} else {
fprintf(stderr,
"Transmission mode (R10) %s is not supported\n",
asn1_type.ant_info_r10->explicit_value_r10().tx_mode_r10.to_string().c_str());
}
} else if (asn1_type.ant_info_present &&
asn1_type.ant_info.type() == asn1::rrc::phys_cfg_ded_s::ant_info_c_::types::explicit_value) {
// Parse Release 8
asn1::rrc::ant_info_ded_s::tx_mode_e_::options tx_mode = asn1_type.ant_info.explicit_value().tx_mode.value;
if ((srslte_tm_t)tx_mode < SRSLTE_TMINV) {
cfg->dl_cfg.tm = (srslte_tm_t)tx_mode;
} else {
fprintf(stderr,
"Transmission mode (R8) %s is not supported\n",
asn1_type.ant_info.explicit_value().tx_mode.to_string().c_str());
}
}
if (asn1_type.sched_request_cfg_present) {
if (asn1_type.sched_request_cfg_present and asn1_type.sched_request_cfg.type() == asn1::rrc::setup_e::setup) {
cfg->ul_cfg.pucch.I_sr = asn1_type.sched_request_cfg.setup().sr_cfg_idx;
cfg->ul_cfg.pucch.n_pucch_sr = asn1_type.sched_request_cfg.setup().sr_pucch_res_idx;
cfg->ul_cfg.pucch.sr_configured = true;
} else {
cfg->ul_cfg.pucch.I_sr = 0;
cfg->ul_cfg.pucch.n_pucch_sr = 0;
cfg->ul_cfg.pucch.sr_configured = false;
}
}
if (asn1_type.pdsch_cfg_ded_present) {
// Configure PDSCH
if (asn1_type.pdsch_cfg_ded_present && cfg->dl_cfg.pdsch.p_b < 4) {
cfg->dl_cfg.pdsch.p_a = asn1_type.pdsch_cfg_ded.p_a.to_number();
cfg->dl_cfg.pdsch.power_scale = true;
} else {
cfg->dl_cfg.pdsch.power_scale = false;
}
}
}
void set_phy_cfg_t_common_prach(phy_cfg_t* cfg, const asn1::rrc::prach_cfg_info_s* asn1_type, uint32_t root_seq_idx)
{
if (asn1_type) {
cfg->prach_cfg.config_idx = asn1_type->prach_cfg_idx;
cfg->prach_cfg.zero_corr_zone = asn1_type->zero_correlation_zone_cfg;
cfg->prach_cfg.freq_offset = asn1_type->prach_freq_offset;
cfg->prach_cfg.hs_flag = asn1_type->high_speed_flag;
}
cfg->prach_cfg.root_seq_idx = root_seq_idx;
}
void set_phy_cfg_t_common_pdsch(phy_cfg_t* cfg, const asn1::rrc::pdsch_cfg_common_s& asn1_type)
{
cfg->dl_cfg.pdsch.rs_power = (float)asn1_type.ref_sig_pwr;
cfg->dl_cfg.pdsch.p_b = asn1_type.p_b;
}
void set_phy_cfg_t_enable_64qam(phy_cfg_t* cfg, const bool enabled)
{
cfg->ul_cfg.pusch.enable_64qam = enabled;
}
void set_phy_cfg_t_common_pusch(phy_cfg_t* cfg, const asn1::rrc::pusch_cfg_common_s& asn1_type)
{
/* PUSCH DMRS signal configuration */
bzero(&cfg->ul_cfg.dmrs, sizeof(srslte_refsignal_dmrs_pusch_cfg_t));
cfg->ul_cfg.dmrs.group_hopping_en = asn1_type.ul_ref_sigs_pusch.group_hop_enabled;
cfg->ul_cfg.dmrs.sequence_hopping_en = asn1_type.ul_ref_sigs_pusch.seq_hop_enabled;
cfg->ul_cfg.dmrs.cyclic_shift = asn1_type.ul_ref_sigs_pusch.cyclic_shift;
cfg->ul_cfg.dmrs.delta_ss = asn1_type.ul_ref_sigs_pusch.group_assign_pusch;
/* PUSCH Hopping configuration */
bzero(&cfg->ul_cfg.hopping, sizeof(srslte_pusch_hopping_cfg_t));
cfg->ul_cfg.hopping.n_sb = asn1_type.pusch_cfg_basic.n_sb;
cfg->ul_cfg.hopping.hopping_offset = asn1_type.pusch_cfg_basic.pusch_hop_offset;
cfg->ul_cfg.hopping.hop_mode =
asn1_type.pusch_cfg_basic.hop_mode.value ==
asn1::rrc::pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame
? cfg->ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF
: cfg->ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF;
}
void set_phy_cfg_t_common_pucch(phy_cfg_t* cfg, const asn1::rrc::pucch_cfg_common_s& asn1_type)
{
/* PUCCH configuration */
cfg->ul_cfg.pucch.delta_pucch_shift = asn1_type.delta_pucch_shift.to_number();
cfg->ul_cfg.pucch.N_cs = asn1_type.n_cs_an;
cfg->ul_cfg.pucch.n_rb_2 = asn1_type.n_rb_cqi;
cfg->ul_cfg.pucch.N_pucch_1 = asn1_type.n1_pucch_an;
}
void set_phy_cfg_t_common_srs(phy_cfg_t* cfg, const asn1::rrc::srs_ul_cfg_common_c& asn1_type)
{
cfg->ul_cfg.srs.common_enabled = asn1_type.type() == asn1::rrc::setup_e::setup;
if (cfg->ul_cfg.srs.common_enabled) {
cfg->ul_cfg.srs.simul_ack = asn1_type.setup().ack_nack_srs_simul_tx;
cfg->ul_cfg.srs.bw_cfg = asn1_type.setup().srs_bw_cfg.to_number();
cfg->ul_cfg.srs.subframe_config = asn1_type.setup().srs_sf_cfg.to_number();
}
}
void set_phy_cfg_t_common_pwr_ctrl(phy_cfg_t* cfg, const asn1::rrc::ul_pwr_ctrl_common_s& asn1_type)
{
cfg->ul_cfg.power_ctrl.p0_nominal_pusch = asn1_type.p0_nominal_pusch;
cfg->ul_cfg.power_ctrl.alpha = asn1_type.alpha.to_number();
cfg->ul_cfg.power_ctrl.p0_nominal_pucch = asn1_type.p0_nominal_pucch;
cfg->ul_cfg.power_ctrl.delta_f_pucch[0] = asn1_type.delta_flist_pucch.delta_f_pucch_format1.to_number();
cfg->ul_cfg.power_ctrl.delta_f_pucch[1] = asn1_type.delta_flist_pucch.delta_f_pucch_format1b.to_number();
cfg->ul_cfg.power_ctrl.delta_f_pucch[2] = asn1_type.delta_flist_pucch.delta_f_pucch_format2.to_number();
cfg->ul_cfg.power_ctrl.delta_f_pucch[3] = asn1_type.delta_flist_pucch.delta_f_pucch_format2a.to_number();
cfg->ul_cfg.power_ctrl.delta_f_pucch[4] = asn1_type.delta_flist_pucch.delta_f_pucch_format2b.to_number();
cfg->ul_cfg.power_ctrl.delta_preamble_msg3 = asn1_type.delta_preamb_msg3;
}
void set_phy_cfg_t_scell_config(phy_cfg_t* cfg, const asn1::rrc::scell_to_add_mod_r10_s& asn1_type)
{
if (asn1_type.rr_cfg_common_scell_r10_present) {
// Enable always CSI request extra bit
cfg->dl_cfg.dci.multiple_csi_request_enabled = true;
auto* rr_cfg_common_scell_r10 = &asn1_type.rr_cfg_common_scell_r10;
if (rr_cfg_common_scell_r10->ul_cfg_r10_present) {
auto* ul_cfg_r10 = &rr_cfg_common_scell_r10->ul_cfg_r10;
// Parse Power control
auto* ul_pwr_ctrl_common_scell_r10 = &ul_cfg_r10->ul_pwr_ctrl_common_scell_r10;
bzero(&cfg->ul_cfg.power_ctrl, sizeof(srslte_ue_ul_powerctrl_t));
cfg->ul_cfg.power_ctrl.p0_nominal_pusch = ul_pwr_ctrl_common_scell_r10->p0_nominal_pusch_r10;
cfg->ul_cfg.power_ctrl.alpha = ul_pwr_ctrl_common_scell_r10->alpha_r10.to_number();
// Parse SRS
cfg->ul_cfg.srs.common_enabled = ul_cfg_r10->srs_ul_cfg_common_r10.type() == asn1::rrc::setup_e::setup;
if (cfg->ul_cfg.srs.common_enabled) {
auto* srs_ul_cfg_common = &ul_cfg_r10->srs_ul_cfg_common_r10.setup();
cfg->ul_cfg.srs.simul_ack = srs_ul_cfg_common->ack_nack_srs_simul_tx;
cfg->ul_cfg.srs.bw_cfg = srs_ul_cfg_common->srs_bw_cfg.to_number();
cfg->ul_cfg.srs.subframe_config = srs_ul_cfg_common->srs_sf_cfg.to_number();
}
// Parse PUSCH
auto* pusch_cfg_common = &ul_cfg_r10->pusch_cfg_common_r10;
bzero(&cfg->ul_cfg.hopping, sizeof(srslte_pusch_hopping_cfg_t));
cfg->ul_cfg.hopping.n_sb = pusch_cfg_common->pusch_cfg_basic.n_sb;
cfg->ul_cfg.hopping.hop_mode =
pusch_cfg_common->pusch_cfg_basic.hop_mode.value ==
asn1::rrc::pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame
? cfg->ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF
: cfg->ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF;
cfg->ul_cfg.hopping.hopping_offset = pusch_cfg_common->pusch_cfg_basic.pusch_hop_offset;
cfg->ul_cfg.pusch.enable_64qam = pusch_cfg_common->pusch_cfg_basic.enable64_qam;
}
}
if (asn1_type.rr_cfg_ded_scell_r10_present) {
auto* rr_cfg_ded_scell_r10 = &asn1_type.rr_cfg_ded_scell_r10;
if (rr_cfg_ded_scell_r10->phys_cfg_ded_scell_r10_present) {
auto* phys_cfg_ded_scell_r10 = &rr_cfg_ded_scell_r10->phys_cfg_ded_scell_r10;
// Parse nonUL Configuration
if (phys_cfg_ded_scell_r10->non_ul_cfg_r10_present) {
auto* non_ul_cfg = &phys_cfg_ded_scell_r10->non_ul_cfg_r10;
// Parse Transmission mode
if (non_ul_cfg->ant_info_r10_present) {
if (non_ul_cfg->ant_info_r10.tx_mode_r10.to_number() < (uint8_t)SRSLTE_TMINV) {
cfg->dl_cfg.tm = (srslte_tm_t)non_ul_cfg->ant_info_r10.tx_mode_r10.to_number();
} else {
fprintf(stderr,
"Transmission mode (R10) %s is not supported\n",
non_ul_cfg->ant_info_r10.tx_mode_r10.to_string().c_str());
}
}
// Parse Cross carrier scheduling
if (non_ul_cfg->cross_carrier_sched_cfg_r10_present) {
typedef asn1::rrc::cross_carrier_sched_cfg_r10_s::sched_cell_info_r10_c_ sched_info_t;
typedef sched_info_t::types cross_carrier_type_e;
auto* sched_info = &non_ul_cfg->cross_carrier_sched_cfg_r10.sched_cell_info_r10;
cross_carrier_type_e cross_carrier_type = sched_info->type();
if (cross_carrier_type == cross_carrier_type_e::own_r10) {
cfg->dl_cfg.dci.cif_present = sched_info->own_r10().cif_presence_r10;
} else {
cfg->dl_cfg.dci.cif_present = false; // This CC does not have Carrier Indicator Field
// ue_cfg->dl_cfg.blablabla = sched_info->other_r10().pdsch_start_r10;
// ue_cfg->dl_cfg.blablabla = sched_info->other_r10().sched_cell_id_r10;
}
}
// Parse pdsch config dedicated
if (non_ul_cfg->pdsch_cfg_ded_r10_present) {
cfg->dl_cfg.pdsch.p_b = asn1_type.rr_cfg_common_scell_r10.non_ul_cfg_r10.pdsch_cfg_common_r10.p_b;
cfg->dl_cfg.pdsch.p_a = non_ul_cfg->pdsch_cfg_ded_r10.p_a.to_number();
cfg->dl_cfg.pdsch.power_scale = true;
}
}
// Parse UL Configuration
if (phys_cfg_ded_scell_r10->ul_cfg_r10_present) {
auto* ul_cfg_r10 = &phys_cfg_ded_scell_r10->ul_cfg_r10;
// Parse CQI param
if (ul_cfg_r10->cqi_report_cfg_scell_r10_present) {
auto* cqi_report_cfg = &ul_cfg_r10->cqi_report_cfg_scell_r10;
// Aperiodic report
if (cqi_report_cfg->cqi_report_mode_aperiodic_r10_present) {
cfg->dl_cfg.cqi_report.aperiodic_configured = true;
cfg->dl_cfg.cqi_report.aperiodic_mode = make_aperiodic_mode(cqi_report_cfg->cqi_report_mode_aperiodic_r10);
}
// Periodic report
if (cqi_report_cfg->cqi_report_periodic_scell_r10_present) {
if (cqi_report_cfg->cqi_report_periodic_scell_r10.type() == asn1::rrc::setup_e::setup) {
typedef asn1::rrc::cqi_report_periodic_r10_c::setup_s_ cqi_cfg_t;
cqi_cfg_t cqi_cfg = cqi_report_cfg->cqi_report_periodic_scell_r10.setup();
cfg->dl_cfg.cqi_report.periodic_configured = true;
cfg->dl_cfg.cqi_report.pmi_idx = cqi_cfg.cqi_pmi_cfg_idx;
cfg->dl_cfg.cqi_report.format_is_subband =
cqi_cfg.cqi_format_ind_periodic_r10.type().value ==
cqi_cfg_t::cqi_format_ind_periodic_r10_c_::types::subband_cqi_r10;
if (cfg->dl_cfg.cqi_report.format_is_subband) {
cfg->dl_cfg.cqi_report.subband_size = cqi_cfg.cqi_format_ind_periodic_r10.subband_cqi_r10().k;
}
if (cqi_cfg.ri_cfg_idx_present) {
cfg->dl_cfg.cqi_report.ri_idx = cqi_cfg.ri_cfg_idx;
cfg->dl_cfg.cqi_report.ri_idx_present = true;
} else {
cfg->dl_cfg.cqi_report.ri_idx_present = false;
}
} else {
// Release, disable periodic reporting
cfg->dl_cfg.cqi_report.periodic_configured = false;
}
}
}
// Sounding reference signals Dedicated
if (ul_cfg_r10->srs_ul_cfg_ded_r10_present) {
cfg->ul_cfg.srs.dedicated_enabled = ul_cfg_r10->srs_ul_cfg_ded_r10.type() == asn1::rrc::setup_e::setup;
if (cfg->ul_cfg.srs.dedicated_enabled) {
auto* srs_ul_cfg_ded_r10 = &ul_cfg_r10->srs_ul_cfg_ded_r10.setup();
cfg->ul_cfg.srs.configured = cfg->ul_cfg.srs.dedicated_enabled and cfg->ul_cfg.srs.common_enabled;
cfg->ul_cfg.srs.I_srs = srs_ul_cfg_ded_r10->srs_cfg_idx;
cfg->ul_cfg.srs.B = srs_ul_cfg_ded_r10->srs_bw;
cfg->ul_cfg.srs.b_hop = srs_ul_cfg_ded_r10->srs_hop_bw;
cfg->ul_cfg.srs.n_rrc = srs_ul_cfg_ded_r10->freq_domain_position;
cfg->ul_cfg.srs.k_tc = srs_ul_cfg_ded_r10->tx_comb;
cfg->ul_cfg.srs.n_srs = srs_ul_cfg_ded_r10->cyclic_shift;
}
}
}
if (phys_cfg_ded_scell_r10->cqi_report_cfg_scell_v1250.is_present()) {
// Enable/disable PDSCH 256QAM
auto cqi_report_cfg_scell = phys_cfg_ded_scell_r10->cqi_report_cfg_scell_v1250.get();
cfg->dl_cfg.pdsch.use_tbs_index_alt = cqi_report_cfg_scell->alt_cqi_table_r12_present;
} else {
// Assume there is no PDSCH 256QAM
cfg->dl_cfg.pdsch.use_tbs_index_alt = false;
}
}
}
}
// MBMS
mbms_notif_cfg_t make_mbms_notif_cfg(const asn1::rrc::mbms_notif_cfg_r9_s& asn1_type)
{
mbms_notif_cfg_t ret{};
ret.notif_repeat_coeff = (mbms_notif_cfg_t::coeff_t)asn1_type.notif_repeat_coeff_r9.value;
ret.notif_offset = asn1_type.notif_offset_r9;
ret.notif_sf_idx = asn1_type.notif_sf_idx_r9;
return ret;
}
mbsfn_area_info_t make_mbsfn_area_info(const asn1::rrc::mbsfn_area_info_r9_s& asn1_type)
{
mbsfn_area_info_t ret{};
ret.mbsfn_area_id = asn1_type.mbsfn_area_id_r9;
ret.non_mbsfn_region_len = (mbsfn_area_info_t::region_len_t)asn1_type.non_mbsfn_region_len.value;
ret.notif_ind = asn1_type.notif_ind_r9;
ret.mcch_cfg.mcch_repeat_period =
(mbsfn_area_info_t::mcch_cfg_t::repeat_period_t)asn1_type.mcch_cfg_r9.mcch_repeat_period_r9.value;
ret.mcch_cfg.mcch_offset = asn1_type.mcch_cfg_r9.mcch_offset_r9;
ret.mcch_cfg.mcch_mod_period =
(mbsfn_area_info_t::mcch_cfg_t::mod_period_t)asn1_type.mcch_cfg_r9.mcch_mod_period_r9.value;
ret.mcch_cfg.sf_alloc_info = asn1_type.mcch_cfg_r9.sf_alloc_info_r9.to_number();
ret.mcch_cfg.sig_mcs = (mbsfn_area_info_t::mcch_cfg_t::sig_mcs_t)asn1_type.mcch_cfg_r9.sig_mcs_r9.value;
return ret;
}
mbsfn_sf_cfg_t make_mbsfn_sf_cfg(const asn1::rrc::mbsfn_sf_cfg_s& sf_cfg)
{
mbsfn_sf_cfg_t cfg{};
cfg.radioframe_alloc_period = (mbsfn_sf_cfg_t::alloc_period_t)sf_cfg.radioframe_alloc_period.value;
cfg.radioframe_alloc_offset = sf_cfg.radioframe_alloc_offset;
cfg.nof_alloc_subfrs = (mbsfn_sf_cfg_t::sf_alloc_type_t)sf_cfg.sf_alloc.type().value;
if (sf_cfg.sf_alloc.type().value == asn1::rrc::mbsfn_sf_cfg_s::sf_alloc_c_::types_opts::one_frame) {
cfg.sf_alloc = sf_cfg.sf_alloc.one_frame().to_number();
} else {
cfg.sf_alloc = sf_cfg.sf_alloc.four_frames().to_number();
}
return cfg;
}
pmch_info_t make_pmch_info(const asn1::rrc::pmch_info_r9_s& asn1_type)
{
pmch_info_t ret{};
ret.sf_alloc_end = asn1_type.pmch_cfg_r9.sf_alloc_end_r9;
ret.data_mcs = asn1_type.pmch_cfg_r9.data_mcs_r9;
ret.mch_sched_period = (pmch_info_t::mch_sched_period_t)asn1_type.pmch_cfg_r9.mch_sched_period_r9.value;
ret.nof_mbms_session_info = asn1_type.mbms_session_info_list_r9.size();
for (uint32_t i = 0; i < ret.nof_mbms_session_info; ++i) {
auto& asn1item = asn1_type.mbms_session_info_list_r9[i];
auto& item = ret.mbms_session_info_list[i];
item.session_id_present = asn1item.session_id_r9_present;
item.lc_ch_id = asn1item.lc_ch_id_r9;
item.session_id = asn1item.session_id_r9[0];
item.tmgi.plmn_id_type = (tmgi_t::plmn_id_type_t)asn1item.tmgi_r9.plmn_id_r9.type().value;
if (item.tmgi.plmn_id_type == tmgi_t::plmn_id_type_t::plmn_idx) {
item.tmgi.plmn_id.plmn_idx = asn1item.tmgi_r9.plmn_id_r9.plmn_idx_r9();
} else {
item.tmgi.plmn_id.explicit_value = make_plmn_id_t(asn1item.tmgi_r9.plmn_id_r9.explicit_value_r9());
}
memcpy(item.tmgi.serviced_id, &asn1item.tmgi_r9.service_id_r9[0], 3);
}
return ret;
}
mcch_msg_t make_mcch_msg(const asn1::rrc::mcch_msg_s& asn1_type)
{
mcch_msg_t msg{};
auto& r9 = asn1_type.msg.c1().mbsfn_area_cfg_r9();
msg.nof_common_sf_alloc = r9.common_sf_alloc_r9.size();
for (uint32_t i = 0; i < msg.nof_common_sf_alloc; ++i) {
msg.common_sf_alloc[i] = make_mbsfn_sf_cfg(r9.common_sf_alloc_r9[i]);
}
msg.common_sf_alloc_period = (mcch_msg_t::common_sf_alloc_period_t)r9.common_sf_alloc_period_r9.value;
msg.nof_pmch_info = r9.pmch_info_list_r9.size();
for (uint32_t i = 0; i < msg.nof_pmch_info; ++i) {
msg.pmch_info_list[i] = make_pmch_info(r9.pmch_info_list_r9[i]);
}
return msg;
}
static_assert(ASN1_RRC_MAX_SESSION_PER_PMCH == pmch_info_t::max_session_per_pmch, "ASN1 to srsLTE interface mismatch");
sib13_t make_sib13(const asn1::rrc::sib_type13_r9_s& asn1_type)
{
sib13_t sib13{};
sib13.nof_mbsfn_area_info = asn1_type.mbsfn_area_info_list_r9.size();
for (uint32_t i = 0; i < asn1_type.mbsfn_area_info_list_r9.size(); ++i) {
sib13.mbsfn_area_info_list[i] = make_mbsfn_area_info(asn1_type.mbsfn_area_info_list_r9[i]);
}
sib13.notif_cfg = make_mbms_notif_cfg(asn1_type.notif_cfg_r9);
return sib13;
}
} // namespace srslte

@ -21,6 +21,9 @@
file(GLOB CXX_SOURCES "*.cc")
file(GLOB C_SOURCES "*.c")
# Avoid warnings caused by libmbedtls about deprecated functions
set_source_files_properties(security.cc PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations)
add_library(srslte_common STATIC ${C_SOURCES} ${CXX_SOURCES})
add_custom_target(gen_build_info COMMAND cmake -P ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake)
add_dependencies(srslte_common gen_build_info)

@ -49,5 +49,5 @@ void byte_buffer_pool::cleanup(void)
}
pthread_mutex_unlock(&instance_mutex);
}
} // namespace srsue
} // namespace srslte

@ -37,6 +37,7 @@
#include "srslte/common/liblte_security.h"
#include "math.h"
#include "srslte/common/liblte_ssl.h"
#include "srslte/common/zuc.h"
/*******************************************************************************
DEFINES
@ -807,6 +808,88 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(
return (err);
}
u32 GET_WORD(u32* DATA, u32 i)
{
u32 WORD, ti;
ti = i % 32;
if (ti == 0)
WORD = DATA[i / 32];
else
WORD = (DATA[i / 32] << ti) | (DATA[i / 32 + 1] >> (32 - ti));
return WORD;
}
u8 GET_BIT(uint8_t* DATA, u32 i)
{
return (DATA[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
}
LIBLTE_ERROR_ENUM liblte_security_128_eia3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* mac)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8_t iv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32* ks;
uint32 msg_len_block_8, msg_len_block_32, m;
if (key != NULL && msg != NULL && mac != NULL) {
msg_len_block_8 = (msg_len + 7) / 8;
msg_len_block_32 = (msg_len + 31) / 32;
// Construct iv
iv[0] = (count >> 24) & 0xFF;
iv[1] = (count >> 16) & 0xFF;
iv[2] = (count >> 8) & 0xFF;
iv[3] = count & 0xFF;
iv[4] = (bearer << 3) & 0xF8;
iv[5] = iv[6] = iv[7] = 0;
iv[8] = ((count >> 24) & 0xFF) ^ ((direction & 1) << 7);
iv[9] = (count >> 16) & 0xFF;
iv[10] = (count >> 8) & 0xFF;
iv[11] = count & 0xFF;
iv[12] = iv[4];
iv[13] = iv[5];
iv[14] = iv[6] ^ ((direction & 1) << 7);
iv[15] = iv[7];
zuc_state_t zuc_state;
// Initialize keystream
zuc_initialize(&zuc_state, key, iv);
// Generate keystream
int N = msg_len + 64;
int L = (N + 31) / 32;
ks = (uint32*)calloc(L, sizeof(uint32));
zuc_generate_keystream(&zuc_state, L, ks);
uint32_t T = 0;
for (uint32_t i = 0; i < msg_len; i++) {
if (GET_BIT(msg, i)) {
T ^= GET_WORD(ks, i);
}
}
T ^= GET_WORD(ks, msg_len);
uint32_t mac_tmp = T ^ ks[L - 1];
mac[0] = (mac_tmp >> 24) & 0xFF;
mac[1] = (mac_tmp >> 16) & 0xFF;
mac[2] = (mac_tmp >> 8) & 0xFF;
mac[3] = mac_tmp & 0xFF;
free(ks);
}
return (err);
}
/*********************************************************************
Name: liblte_security_encryption_eea1
@ -951,6 +1034,89 @@ LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(
return liblte_security_encryption_eea2(key, count, bearer, direction, ct, ct_len, out);
}
/*********************************************************************
Name: liblte_security_encryption_eea1
Description: 128-bit encryption algorithm EEA1.
Document Reference: 33.401 v13.1.0 Annex B.1.2
35.215 v13.0.0 References
Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* out)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8_t iv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32* ks;
int32 i;
uint32 msg_len_block_8, msg_len_block_32, m;
if (key != NULL && msg != NULL && out != NULL) {
msg_len_block_8 = (msg_len + 7) / 8;
msg_len_block_32 = (msg_len + 31) / 32;
// Construct iv
iv[0] = (count >> 24) & 0xFF;
iv[1] = (count >> 16) & 0xFF;
iv[2] = (count >> 8) & 0xFF;
iv[3] = (count)&0xFF;
iv[4] = ((bearer & 0x1F) << 3) | ((direction & 0x01) << 2);
iv[5] = 0;
iv[6] = 0;
iv[7] = 0;
iv[8] = iv[0];
iv[9] = iv[1];
iv[10] = iv[2];
iv[11] = iv[3];
iv[12] = iv[4];
iv[13] = iv[5];
iv[14] = iv[6];
iv[15] = iv[7];
zuc_state_t zuc_state;
// Initialize keystream
zuc_initialize(&zuc_state, key, iv);
// Generate keystream
ks = (uint32*)calloc(msg_len_block_32, sizeof(uint32));
zuc_generate_keystream(&zuc_state, msg_len_block_32, ks);
// Generate output except last block
for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) {
out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF);
out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF);
out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF);
out[4 * i + 3] = msg[4 * i + 3] ^ ((ks[i] & 0xFF));
}
// Process last bytes
for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) {
out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF);
}
// Zero tailing bits
zero_tailing_bits(out, msg_len);
// Clean up
free(ks);
// zuc_deinitialize(state_ptr);
err = LIBLTE_SUCCESS;
}
return (err);
}
LIBLTE_ERROR_ENUM liblte_security_decryption_eea3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* out)
{
return liblte_security_encryption_eea3(key, count, bearer, direction, msg, msg_len, out);
}
/*********************************************************************
Name: liblte_security_milenage_f1

@ -65,216 +65,173 @@ void log_filter::init(std::string layer, logger *logger_, bool tti)
do_tti = tti;
}
void log_filter::all_log(srslte::LOG_LEVEL_ENUM level,
uint32_t tti,
const char *msg)
void log_filter::all_log(
srslte::LOG_LEVEL_ENUM level, uint32_t tti, const char* msg, const uint8_t* hex, int size, bool long_msg)
{
if(logger_h) {
std::stringstream ss;
char buffer_tti[16] = {};
char buffer_time[64] = {};
ss << now_time() << " ";
if (show_layer_en) {
ss << "[" <<get_service_name() << "] ";
}
if (level_text_short) {
ss << log_level_text_short[level] << " ";
if (logger_h) {
logger::unique_log_str_t log_str = nullptr;
if (long_msg) {
// For long messages, dynamically allocate a new log_str with enough size outside the pool.
uint32_t log_str_msg_len = sizeof(buffer_tti) + sizeof(buffer_time) + 20 + size;
log_str = logger::unique_log_str_t(new logger::log_str(nullptr, log_str_msg_len), logger::log_str_deleter());
} else {
ss << log_level_text[level] << " ";
}
if(do_tti) {
ss << "[" << std::setfill('0') << std::setw(5) << tti << "] ";
log_str = logger_h->allocate_unique_log_str();
}
if (add_string_en) {
ss << add_string_val << " ";
}
ss << msg;
str_ptr s_ptr(new std::string(ss.str()));
logger_h->log(s_ptr);
}
}
if (log_str) {
now_time(buffer_time, sizeof(buffer_time));
if (do_tti) {
get_tti_str(tti, buffer_tti, sizeof(buffer_tti));
}
void log_filter::all_log(srslte::LOG_LEVEL_ENUM level,
uint32_t tti,
const char *msg,
const uint8_t *hex,
int size)
{
if(logger_h) {
std::stringstream ss;
snprintf(log_str->str(),
log_str->get_buffer_size(),
"%s [%s] %s %s%s%s%s%s",
buffer_time,
get_service_name().c_str(),
log_level_text_short[level],
do_tti ? buffer_tti : "",
add_string_en ? add_string_val.c_str() : "",
msg,
msg[strlen(msg) - 1] != '\n' ? "\n" : "",
(hex_limit > 0 && hex && size > 0) ? hex_string(hex, size).c_str() : "");
ss << now_time() << " ";
if (show_layer_en) {
ss << "[" <<get_service_name() << "] ";
}
if (level_text_short) {
ss << log_level_text_short[level] << " ";
logger_h->log(std::move(log_str));
} else {
ss << log_level_text[level] << " ";
logger_h->log_char("Error in Log: Not enough buffers in pool\n");
}
if(do_tti) {
ss << "[" << std::setfill('0') << std::setw(5) << tti << "] ";
}
if (add_string_en) {
ss << add_string_val << " ";
}
ss << msg;
if (msg[strlen(msg)-1] != '\n') {
ss << std::endl;
}
if (hex_limit > 0 && hex && size > 0) {
ss << hex_string(hex, size);
}
str_ptr s_ptr(new std::string(ss.str()));
logger_h->log(s_ptr);
}
}
void log_filter::console(const char * message, ...) {
char *args_msg = NULL;
char args_msg[char_buff_size];
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
if (vsnprintf(args_msg, char_buff_size, message, args) > 0)
printf("%s",args_msg); // Print directly to stdout
fflush(stdout);
va_end(args);
free(args_msg);
}
#define all_log_expand(log_level) \
do { \
if (level >= log_level) { \
char args_msg[char_buff_size]; \
va_list args; \
va_start(args, message); \
if (vsnprintf(args_msg, char_buff_size, message, args) > 0) \
all_log(log_level, tti, args_msg); \
va_end(args); \
} \
} while (0)
#define all_log_hex_expand(log_level) \
do { \
if (level >= log_level) { \
char args_msg[char_buff_size]; \
va_list args; \
va_start(args, message); \
if (vsnprintf(args_msg, char_buff_size, message, args) > 0) \
all_log(log_level, tti, args_msg, hex, size); \
va_end(args); \
} \
} while (0)
void log_filter::error(const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) {
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_ERROR, tti, args_msg);
va_end(args);
free(args_msg);
}
all_log_expand(LOG_LEVEL_ERROR);
}
void log_filter::warning(const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) {
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_WARNING, tti, args_msg);
va_end(args);
free(args_msg);
}
all_log_expand(LOG_LEVEL_WARNING);
}
void log_filter::info(const char * message, ...) {
if (level >= LOG_LEVEL_INFO) {
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_INFO, tti, args_msg);
va_end(args);
free(args_msg);
}
all_log_expand(LOG_LEVEL_INFO);
}
void log_filter::debug(const char * message, ...) {
all_log_expand(LOG_LEVEL_DEBUG);
}
void log_filter::debug_long(const char* message, ...)
{
if (level >= LOG_LEVEL_DEBUG) {
char *args_msg = NULL;
char* args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_DEBUG, tti, args_msg);
if (vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_DEBUG, tti, args_msg, nullptr, strlen(args_msg), true);
va_end(args);
free(args_msg);
}
}
void log_filter::error_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) {
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_ERROR, tti, args_msg, hex, size);
va_end(args);
free(args_msg);
}
all_log_hex_expand(LOG_LEVEL_ERROR);
}
void log_filter::warning_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) {
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_WARNING, tti, args_msg, hex, size);
va_end(args);
free(args_msg);
}
all_log_hex_expand(LOG_LEVEL_WARNING);
}
void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_INFO) {
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_INFO, tti, args_msg, hex, size);
va_end(args);
free(args_msg);
}
all_log_hex_expand(LOG_LEVEL_INFO);
}
void log_filter::debug_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_DEBUG) {
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_DEBUG, tti, args_msg, hex, size);
va_end(args);
free(args_msg);
}
all_log_hex_expand(LOG_LEVEL_DEBUG);
}
void log_filter::set_time_src(time_itf *source, time_format_t format) {
this->time_src = source;
this->time_format = format;
}
void log_filter::get_tti_str(const uint32_t tti_, char* buffer, const uint32_t buffer_len)
{
snprintf(buffer, buffer_len, "[%5d] ", tti_);
}
std::string log_filter::now_time()
void log_filter::now_time(char* buffer, const uint32_t buffer_len)
{
struct timeval rawtime;
struct tm * timeinfo;
char buffer[64];
char us[16];
srslte_timestamp_t now;
uint64_t usec_epoch;
if (buffer_len < 16) {
fprintf(stderr, "Error buffer provided for time too small\n");
return;
}
if (!time_src) {
gettimeofday(&rawtime, NULL);
timeinfo = localtime(&rawtime.tv_sec);
if (time_format == TIME) {
strftime(buffer, 64, "%H:%M:%S", timeinfo);
strcat(buffer, ".");
strftime(buffer, buffer_len, "%H:%M:%S.", timeinfo);
snprintf(us, 16, "%06ld", rawtime.tv_usec);
strcat(buffer, us);
uint32_t dest_len = strlen(buffer);
strncat(buffer, us, buffer_len - dest_len - 1);
} else {
usec_epoch = rawtime.tv_sec * 1000000 + rawtime.tv_usec;
snprintf(buffer, 64, "%ld", usec_epoch);
snprintf(buffer, buffer_len, "%ld", usec_epoch);
}
} else {
now = time_src->get_time();
if (time_format == TIME) {
snprintf(buffer, 64, "%ld:%06u", now.full_secs, (uint32_t) (now.frac_secs * 1e6));
snprintf(buffer, buffer_len, "%ld:%06u", now.full_secs, (uint32_t)(now.frac_secs * 1e6));
} else {
usec_epoch = now.full_secs * 1000000 + (uint32_t) (now.frac_secs * 1e6);
snprintf(buffer, 64, "%ld", usec_epoch);
snprintf(buffer, buffer_len, "%ld", usec_epoch);
}
}
return std::string(buffer);
}
std::string log_filter::hex_string(const uint8_t *hex, int size)
@ -297,4 +254,4 @@ std::string log_filter::hex_string(const uint8_t *hex, int size)
return ss.str();
}
} // namespace srsue
} // namespace srslte

@ -33,44 +33,58 @@ logger_file::logger_file() : logfile(NULL), is_running(false), cur_length(0), ma
pthread_cond_init(&not_empty, NULL);
}
logger_file::~logger_file() {
if(is_running) {
log(new std::string("Closing log\n"));
pthread_mutex_lock(&mutex);
is_running = false;
pthread_cond_signal(&not_empty); // wakeup thread and let it terminate
pthread_mutex_unlock(&mutex);
wait_thread_finish();
flush();
if (logfile) {
fclose(logfile);
}
}
logger_file::~logger_file()
{
stop();
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&not_empty);
}
void logger_file::init(std::string file, int max_length_) {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&not_empty, NULL);
if (is_running) {
fprintf(stderr, "Error: logger thread is already running.\n");
return;
}
pthread_mutex_lock(&mutex);
max_length = (int64_t)max_length_*1024;
name_idx = 0;
filename = file;
logfile = fopen(filename.c_str(), "w");
if(logfile == NULL) {
if (logfile == NULL) {
printf("Error: could not create log file, no messages will be logged!\n");
}
is_running = true;
start(-2);
pthread_mutex_unlock(&mutex);
}
void logger_file::log(const char *msg) {
log(new std::string(msg));
void logger_file::stop()
{
if (is_running) {
logger::log_char("Closing log\n");
pthread_mutex_lock(&mutex);
is_running = false;
pthread_cond_signal(&not_empty); // wakeup thread and let it terminate
pthread_mutex_unlock(&mutex);
wait_thread_finish();
pthread_mutex_lock(&mutex);
flush();
if (logfile) {
fclose(logfile);
logfile = NULL;
}
pthread_mutex_unlock(&mutex);
} else {
pthread_mutex_lock(&mutex);
flush(); // flush even if thread isn't running anymore
pthread_mutex_unlock(&mutex);
}
}
void logger_file::log(str_ptr msg) {
void logger_file::log(unique_log_str_t msg)
{
pthread_mutex_lock(&mutex);
buffer.push_back(msg);
buffer.push_back(std::move(msg));
pthread_cond_signal(&not_empty);
pthread_mutex_unlock(&mutex);
}
@ -85,13 +99,14 @@ void logger_file::run_thread() {
return; // Thread done. Messages in buffer will be handled in flush.
}
}
str_ptr s = buffer.front();
unique_log_str_t s = std::move(buffer.front());
int n = 0;
if(logfile)
n = fprintf(logfile, "%s", s->c_str());
delete s;
if (logfile) {
n = fprintf(logfile, "%s", s->str());
}
buffer.pop_front();
pthread_mutex_unlock(&mutex);
if (n > 0) {
cur_length += (int64_t) n;
if (cur_length >= max_length && max_length > 0) {
@ -107,18 +122,20 @@ void logger_file::run_thread() {
cur_length = 0;
}
}
pthread_mutex_unlock(&mutex);
}
}
void logger_file::flush() {
std::deque<str_ptr>::iterator it;
for(it=buffer.begin();it!=buffer.end();it++)
{
str_ptr s = *it;
if(logfile)
fprintf(logfile, "%s", s->c_str());
delete s;
void logger_file::flush()
{
std::deque<unique_log_str_t>::iterator it;
for (it = buffer.begin(); it != buffer.end(); it++) {
unique_log_str_t s = std::move(*it);
if (logfile) {
fprintf(logfile, "%s", s->str());
}
}
buffer.clear();
}
} // namespace srsue
} // namespace srslte

@ -0,0 +1,117 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/mac_nr_pcap.h"
#include "srslte/srslte.h"
#include <stdint.h>
namespace srslte {
mac_nr_pcap::mac_nr_pcap() {}
mac_nr_pcap::~mac_nr_pcap()
{
if (pcap_file) {
close();
}
}
void mac_nr_pcap::enable(const bool& enable_)
{
enable_write = enable_;
}
void mac_nr_pcap::open(const std::string& filename_, const uint16_t& ue_id_)
{
fprintf(stdout, "Opening MAC-NR PCAP with DLT=%d\n", UDP_DLT);
filename = filename_;
pcap_file = LTE_PCAP_Open(UDP_DLT, filename.c_str());
ue_id = ue_id_;
enable_write = true;
}
void mac_nr_pcap::close()
{
enable_write = false;
fprintf(stdout, "Saving MAC-NR PCAP to %s\n", filename.c_str());
LTE_PCAP_Close(pcap_file);
pcap_file = nullptr;
}
void mac_nr_pcap::set_ue_id(const uint16_t& ue_id_)
{
ue_id = ue_id_;
}
void mac_nr_pcap::pack_and_write(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint32_t tti,
uint16_t crnti,
uint8_t harqid,
uint8_t direction,
uint8_t rnti_type)
{
if (enable_write) {
mac_nr_context_info_t context = {};
context.radioType = FDD_RADIO;
context.direction = direction;
context.rntiType = rnti_type;
context.rnti = crnti;
context.ueid = ue_id;
context.harqid = harqid;
context.system_frame_number = tti / 10;
context.sub_frame_number = tti % 10;
if (pdu) {
NR_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
}
}
}
void mac_nr_pcap::write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_nr_pcap::write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_UPLINK, C_RNTI);
}
void mac_nr_pcap::write_dl_ra_rnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, RA_RNTI);
}
void mac_nr_pcap::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, NO_RNTI);
}
void mac_nr_pcap::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, P_RNTI);
}
void mac_nr_pcap::write_dl_si_rnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, SI_RNTI);
}
} // namespace srslte

@ -0,0 +1,275 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/mac_nr_pdu.h"
namespace srslte {
mac_nr_sch_subpdu::mac_nr_sch_subpdu(mac_nr_sch_pdu* parent_) : parent(parent_) {}
mac_nr_sch_subpdu::nr_lcid_sch_t mac_nr_sch_subpdu::get_type()
{
if (lcid >= 32) {
return (nr_lcid_sch_t)lcid;
}
return CCCH;
}
bool mac_nr_sch_subpdu::is_sdu()
{
return get_type() == CCCH;
}
bool mac_nr_sch_subpdu::is_var_len_ce()
{
return false;
}
// return length of PDU
uint32_t mac_nr_sch_subpdu::read_subheader(const uint8_t* ptr)
{
// Skip R, read F bit and LCID
F_bit = (bool)(*ptr & 0x40) ? true : false;
lcid = (uint8_t)*ptr & 0x3f;
ptr++;
header_length = 1;
if (is_sdu() || is_var_len_ce()) {
// Read first length byte
sdu_length = (uint32_t)*ptr;
ptr++;
header_length++;
if (F_bit) {
// add second length byte
sdu_length = sdu_length << 8 | ((uint32_t)*ptr & 0xff);
ptr++;
header_length++;
}
} else {
sdu_length = sizeof_ce(lcid, parent->is_ulsch());
}
sdu = (uint8_t*)ptr;
return header_length;
}
void mac_nr_sch_subpdu::set_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_)
{
lcid = lcid_;
sdu = const_cast<uint8_t*>(payload_);
sdu_length = len_;
header_length = 2;
if (sdu_length >= 256) {
F_bit = true;
header_length += 1;
}
}
void mac_nr_sch_subpdu::set_padding(const uint32_t len_)
{
lcid = PADDING;
// 1 Byte R/LCID MAC subheader
sdu_length = len_ - 1;
header_length = 1;
}
// Section 6.1.2
uint32_t mac_nr_sch_subpdu::write_subpdu(const uint8_t* start_)
{
uint8_t* ptr = const_cast<uint8_t*>(start_);
*ptr = (uint8_t)((F_bit ? 1 : 0) << 6) | ((uint8_t)lcid & 0x3f);
ptr += 1;
if (header_length == 3) {
// 3 Byte R/F/LCID/L MAC subheader with 16-bit L field
*ptr = ((sdu_length & 0xff00) >> 8);
ptr += 1;
*ptr = static_cast<uint8_t>(sdu_length);
ptr += 1;
} else if (header_length == 2) {
// 2 Byte R/F/LCID/L MAC subheader with 8-bit L field
*ptr = static_cast<uint8_t>(sdu_length);
ptr += 1;
} else if (header_length == 1) {
// do nothing
} else {
fprintf(stderr, "Error while packing PDU. Unsupported header length (%d)\n", header_length);
}
// copy SDU payload
if (sdu) {
memcpy(ptr, sdu, sdu_length);
} else {
// clear memory
memset(ptr, 0, sdu_length);
}
ptr += sdu_length;
// return total length of subpdu
return ptr - start_;
}
uint32_t mac_nr_sch_subpdu::get_total_length()
{
return (header_length + sdu_length);
}
uint32_t mac_nr_sch_subpdu::get_sdu_length()
{
return sdu_length;
}
uint32_t mac_nr_sch_subpdu::get_lcid()
{
return lcid;
}
uint8_t* mac_nr_sch_subpdu::get_sdu()
{
return sdu;
}
uint32_t mac_nr_sch_subpdu::sizeof_ce(uint32_t lcid, bool is_ul)
{
if (is_ul) {
switch (lcid) {
case CRNTI:
return 2;
case SHORT_TRUNC_BSR:
return 1;
case SHORT_BSR:
return 1;
case PADDING:
return 0;
}
} else {
switch (lcid) {
case CON_RES_ID:
return 6;
case TA_CMD:
return 1;
case DRX_CMD:
return 0;
case PADDING:
return 0;
}
}
return 0;
}
void mac_nr_sch_pdu::pack()
{
// SDUs are written in place, only add padding if needed
if (remaining_len) {
mac_nr_sch_subpdu padding_subpdu(this);
padding_subpdu.set_padding(remaining_len);
padding_subpdu.write_subpdu(buffer->msg + buffer->N_bytes);
// update length
buffer->N_bytes += padding_subpdu.get_total_length();
remaining_len -= padding_subpdu.get_total_length();
subpdus.push_back(padding_subpdu);
}
}
void mac_nr_sch_pdu::unpack(const uint8_t* payload, const uint32_t& len)
{
uint32_t offset = 0;
while (offset < len) {
mac_nr_sch_subpdu sch_pdu(this);
sch_pdu.read_subheader(payload + offset);
offset += sch_pdu.get_total_length();
subpdus.push_back(sch_pdu);
}
if (offset != len) {
fprintf(stderr, "Error parsing NR MAC PDU (len=%d, offset=%d)\n", len, offset);
}
}
uint32_t mac_nr_sch_pdu::get_num_subpdus()
{
return subpdus.size();
}
const mac_nr_sch_subpdu& mac_nr_sch_pdu::get_subpdu(const uint32_t& index)
{
return subpdus.at(index);
}
bool mac_nr_sch_pdu::is_ulsch()
{
return ulsch;
}
void mac_nr_sch_pdu::init_tx(byte_buffer_t* buffer_, uint32_t pdu_len_, bool ulsch_)
{
buffer = buffer_;
pdu_len = pdu_len_;
remaining_len = pdu_len_;
ulsch = ulsch_;
}
uint32_t mac_nr_sch_pdu::size_header_sdu(const uint32_t nbytes)
{
if (nbytes < 256) {
return 2;
} else {
return 3;
}
}
uint32_t mac_nr_sch_pdu::get_remaing_len()
{
return remaining_len;
}
uint32_t mac_nr_sch_pdu::add_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_)
{
int header_size = size_header_sdu(len_);
if (header_size + len_ > remaining_len) {
printf("Header and SDU exceed space in PDU (%d > %d).\n", header_size + len_, remaining_len);
return SRSLTE_ERROR;
}
mac_nr_sch_subpdu sch_pdu(this);
sch_pdu.set_sdu(lcid_, payload_, len_);
uint32_t length = sch_pdu.write_subpdu(buffer->msg + buffer->N_bytes);
if (length != sch_pdu.get_total_length()) {
fprintf(stderr, "Error writing subPDU (Length error: %d != %d)\n", length, sch_pdu.get_total_length());
return SRSLTE_ERROR;
}
// update length and advance payload pointer
buffer->N_bytes += length;
remaining_len -= length;
subpdus.push_back(sch_pdu);
return SRSLTE_SUCCESS;
}
} // namespace srslte

@ -177,7 +177,7 @@ uint8_t* sch_pdu::write_packet(srslte::log* log_h)
// Print warning if we have padding only
if (nof_subheaders <= 0 && nof_subheaders < (int)max_subheaders) {
log_h->warning("Writing MAC PDU with padding only (%d B)\n", pdu_len);
log_h->debug("Writing MAC PDU with padding only (%d B)\n", pdu_len);
}
/* Sanity check and print if error */
@ -556,9 +556,9 @@ bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format)
uint32_t ce_size = format == LONG_BSR ? 3 : 1;
if (((sch_pdu*)parent)->has_space_ce(ce_size)) {
if (format == LONG_BSR) {
w_payload_ce[0] = (buff_size_table(buff_size[0]) & 0x3f) << 2 | (buff_size_table(buff_size[1]) & 0xc0) >> 6;
w_payload_ce[1] = (buff_size_table(buff_size[1]) & 0xf) << 4 | (buff_size_table(buff_size[2]) & 0xf0) >> 4;
w_payload_ce[2] = (buff_size_table(buff_size[2]) & 0x3) << 6 | (buff_size_table(buff_size[3]) & 0x3f);
w_payload_ce[0] = ((buff_size_table(buff_size[0]) & 0x3f) << 2) | ((buff_size_table(buff_size[1]) & 0x30) >> 4);
w_payload_ce[1] = ((buff_size_table(buff_size[1]) & 0xf) << 4) | ((buff_size_table(buff_size[2]) & 0x3c) >> 2);
w_payload_ce[2] = ((buff_size_table(buff_size[2]) & 0x3) << 6) | ((buff_size_table(buff_size[3]) & 0x3f));
} else {
w_payload_ce[0] = (nonzero_lcg & 0x3) << 6 | (buff_size_table(buff_size[nonzero_lcg]) & 0x3f);
}

@ -32,8 +32,8 @@ void rlc_pcap::enable(bool en)
}
void rlc_pcap::open(const char* filename, uint32_t ue_id)
{
fprintf(stdout, "Opening RLC PCAP with DLT=%d\n", RLC_LTE_DLT);
pcap_file = LTE_PCAP_Open(RLC_LTE_DLT, filename);
fprintf(stdout, "Opening RLC PCAP with DLT=%d\n", UDP_DLT);
pcap_file = LTE_PCAP_Open(UDP_DLT, filename);
this->ue_id = ue_id;
enable_write = true;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save